diff options
Diffstat (limited to 'Kernel/Devices')
-rw-r--r-- | Kernel/Devices/HID/HIDManagement.cpp | 7 | ||||
-rw-r--r-- | Kernel/Devices/HID/HIDManagement.h | 2 | ||||
-rw-r--r-- | Kernel/Devices/HID/I8042Controller.cpp | 387 | ||||
-rw-r--r-- | Kernel/Devices/HID/I8042Controller.h | 164 | ||||
-rw-r--r-- | Kernel/Devices/HID/PS2KeyboardDevice.cpp | 116 | ||||
-rw-r--r-- | Kernel/Devices/HID/PS2KeyboardDevice.h | 49 | ||||
-rw-r--r-- | Kernel/Devices/HID/PS2MouseDevice.cpp | 223 | ||||
-rw-r--r-- | Kernel/Devices/HID/PS2MouseDevice.h | 63 | ||||
-rw-r--r-- | Kernel/Devices/HID/VMWareMouseDevice.cpp | 60 | ||||
-rw-r--r-- | Kernel/Devices/HID/VMWareMouseDevice.h | 31 |
10 files changed, 8 insertions, 1094 deletions
diff --git a/Kernel/Devices/HID/HIDManagement.cpp b/Kernel/Devices/HID/HIDManagement.cpp index 7641c0514c..0bb8bc8a53 100644 --- a/Kernel/Devices/HID/HIDManagement.cpp +++ b/Kernel/Devices/HID/HIDManagement.cpp @@ -4,10 +4,13 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include <AK/Platform.h> #include <AK/Singleton.h> +#if ARCH(I386) || ARCH(X86_64) +# include <Kernel/Arch/x86/ISABus/I8042Controller.h> +#endif #include <Kernel/CommandLine.h> #include <Kernel/Devices/HID/HIDManagement.h> -#include <Kernel/Devices/HID/I8042Controller.h> #include <Kernel/Firmware/ACPI/Parser.h> #include <Kernel/Sections.h> @@ -119,6 +122,7 @@ UNMAP_AFTER_INIT ErrorOr<void> HIDManagement::enumerate() // set to emulate PS/2, we should not initialize the PS/2 controller. if (kernel_command_line().disable_ps2_controller()) return {}; +#if ARCH(I386) || ARCH(X86_64) m_i8042_controller = I8042Controller::initialize(); // Note: If ACPI is disabled or doesn't indicate that we have an i8042, we @@ -140,6 +144,7 @@ UNMAP_AFTER_INIT ErrorOr<void> HIDManagement::enumerate() if (m_i8042_controller->keyboard()) m_hid_devices.append(m_i8042_controller->keyboard().release_nonnull()); +#endif return {}; } diff --git a/Kernel/Devices/HID/HIDManagement.h b/Kernel/Devices/HID/HIDManagement.h index 86f242945f..c2c212ddfc 100644 --- a/Kernel/Devices/HID/HIDManagement.h +++ b/Kernel/Devices/HID/HIDManagement.h @@ -61,7 +61,9 @@ private: size_t m_mouse_minor_number { 0 }; size_t m_keyboard_minor_number { 0 }; KeyboardClient* m_client { nullptr }; +#if ARCH(I386) || ARCH(X86_64) LockRefPtr<I8042Controller> m_i8042_controller; +#endif NonnullLockRefPtrVector<HIDDevice> m_hid_devices; Spinlock m_client_lock { LockRank::None }; }; diff --git a/Kernel/Devices/HID/I8042Controller.cpp b/Kernel/Devices/HID/I8042Controller.cpp deleted file mode 100644 index bf48056068..0000000000 --- a/Kernel/Devices/HID/I8042Controller.cpp +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright (c) 2020, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include <Kernel/Arch/Delay.h> -#include <Kernel/Arch/x86/IO.h> -#include <Kernel/Devices/HID/I8042Controller.h> -#include <Kernel/Devices/HID/PS2KeyboardDevice.h> -#include <Kernel/Devices/HID/PS2MouseDevice.h> -#include <Kernel/Devices/HID/VMWareMouseDevice.h> -#include <Kernel/Sections.h> - -namespace Kernel { - -UNMAP_AFTER_INIT NonnullLockRefPtr<I8042Controller> I8042Controller::initialize() -{ - return adopt_lock_ref(*new I8042Controller()); -} - -LockRefPtr<MouseDevice> I8042Controller::mouse() const -{ - return m_mouse_device; -} -LockRefPtr<KeyboardDevice> I8042Controller::keyboard() const -{ - return m_keyboard_device; -} - -UNMAP_AFTER_INIT I8042Controller::I8042Controller() -{ -} - -UNMAP_AFTER_INIT bool I8042Controller::check_existence_via_probing(Badge<HIDManagement>) -{ - { - u8 configuration = 0; - SpinlockLocker lock(m_lock); - - // This drains the output buffer and serves as an existence test. - if (auto result = drain_output_buffer(); result.is_error()) { - dbgln("I8042: Trying to flush output buffer as an existence test failed, error {}", result.error()); - return false; - } - - // Note: Perform controller self-test before touching the controller - // Try to probe the controller for 10 times and give up if nothing - // responded. - // Some controllers will reset and behave abnormally on this, so let's ensure - // we keep the configuration before initiating this command. - - if (auto result = do_wait_then_write(I8042Port::Command, I8042Command::ReadConfiguration); result.is_error()) { - dbgln("I8042: Trying to read configuration failed during the existence test, error {}", result.error()); - return false; - } - - { - auto result = do_wait_then_read(I8042Port::Buffer); - if (result.is_error()) { - dbgln("I8042: Trying to read configuration failed during the existence test, error {}", result.error()); - return false; - } - configuration = result.release_value(); - } - - bool successful_self_test = false; - for (int attempt = 0; attempt < 20; attempt++) { - do_write(I8042Port::Command, I8042Command::TestPS2Controller); - if (do_read(I8042Port::Buffer) == I8042Response::ControllerTestPassed) { - successful_self_test = true; - break; - } - // Note: Wait 500 microseconds in case the controller couldn't respond - microseconds_delay(500); - } - if (!successful_self_test) { - dbgln("I8042: Trying to probe for existence of controller failed"); - return false; - } - - if (auto result = do_wait_then_write(I8042Port::Command, I8042Command::WriteConfiguration); result.is_error()) { - dbgln("I8042: Trying to restore configuration after self-test failed with error {}", result.error()); - return false; - } - - if (auto result = do_wait_then_write(I8042Port::Buffer, configuration); result.is_error()) { - dbgln("I8042: Trying to write restored configuration after self-test failed with error {}", result.error()); - return false; - } - - return true; - } -} - -UNMAP_AFTER_INIT ErrorOr<void> I8042Controller::detect_devices() -{ - - u8 configuration; - { - SpinlockLocker lock(m_lock); - // Note: This flushes all the garbage left in the controller registers - TRY(drain_output_buffer()); - - TRY(do_wait_then_write(I8042Port::Command, I8042Command::DisableFirstPS2Port)); - TRY(do_wait_then_write(I8042Port::Command, I8042Command::DisableSecondPS2Port)); // ignored if it doesn't exist - - TRY(do_wait_then_write(I8042Port::Command, I8042Command::ReadConfiguration)); - configuration = TRY(do_wait_then_read(I8042Port::Buffer)); - TRY(do_wait_then_write(I8042Port::Command, I8042Command::WriteConfiguration)); - configuration &= ~I8042ConfigurationFlag::FirstPS2PortInterrupt; - configuration &= ~I8042ConfigurationFlag::SecondPS2PortInterrupt; - - // Note: The default BIOS on the QEMU microvm machine type (qboot) doesn't - // behave like SeaBIOS, which means it doesn't set first port scan code translation. - // However we rely on compatibility feature of the i8042 to send scan codes of set 1. - // To ensure that the controller is always outputting correct scan codes, set it - // to scan code 2 (because SeaBIOS on regular QEMU machine does this for us) and enable - // first port translation to ensure all scan codes are translated to scan code set 1. - configuration |= I8042ConfigurationFlag::FirstPS2PortTranslation; - TRY(do_wait_then_write(I8042Port::Buffer, configuration)); - TRY(do_wait_then_write(I8042Port::Buffer, I8042Command::SetScanCodeSet)); - TRY(do_wait_then_write(I8042Port::Buffer, 0x2)); - - m_is_dual_channel = (configuration & I8042ConfigurationFlag::SecondPS2PortClock) != 0; - dbgln("I8042: {} channel controller", m_is_dual_channel ? "Dual" : "Single"); - - // Perform controller self-test - TRY(do_wait_then_write(I8042Port::Command, I8042Command::TestPS2Controller)); - auto self_test_result = TRY(do_wait_then_read(I8042Port::Buffer)); - if (self_test_result == I8042Response::ControllerTestPassed) { - // Restore configuration in case the controller reset - TRY(do_wait_then_write(I8042Port::Command, I8042Command::WriteConfiguration)); - TRY(do_wait_then_write(I8042Port::Buffer, configuration)); - } else { - dbgln("I8042: Controller self test failed"); - } - - // Test ports and enable them if available - TRY(do_wait_then_write(I8042Port::Command, I8042Command::TestFirstPS2Port)); - auto first_port_test_result = TRY(do_wait_then_read(I8042Port::Buffer)); - m_first_port_available = (first_port_test_result == 0); - - if (m_first_port_available) { - TRY(do_wait_then_write(I8042Port::Command, I8042Command::EnableFirstPS2Port)); - configuration |= I8042ConfigurationFlag::FirstPS2PortInterrupt; - configuration &= ~I8042ConfigurationFlag::FirstPS2PortClock; - } else { - dbgln("I8042: Keyboard port not available"); - } - - TRY(drain_output_buffer()); - - if (m_is_dual_channel) { - TRY(do_wait_then_write(I8042Port::Command, I8042Command::TestSecondPS2Port)); - auto test_second_port_result = TRY(do_wait_then_read(I8042Port::Buffer)); - m_second_port_available = (test_second_port_result == 0); - if (m_second_port_available) { - TRY(do_wait_then_write(I8042Port::Command, I8042Command::EnableSecondPS2Port)); - configuration |= I8042ConfigurationFlag::SecondPS2PortInterrupt; - configuration &= ~I8042ConfigurationFlag::SecondPS2PortClock; - } else { - dbgln("I8042: Mouse port not available"); - } - } - - // Enable IRQs for the ports that are usable - if (m_first_port_available || m_second_port_available) { - configuration &= ~I8042ConfigurationFlag::FirstPS2PortClock; - configuration &= ~I8042ConfigurationFlag::SecondPS2PortClock; - TRY(do_wait_then_write(I8042Port::Command, I8042Command::WriteConfiguration)); - TRY(do_wait_then_write(I8042Port::Buffer, configuration)); - } - } - - // Try to detect and initialize the devices - if (m_first_port_available) { - auto error_or_device = PS2KeyboardDevice::try_to_initialize(*this); - if (error_or_device.is_error()) { - dbgln("I8042: Keyboard device failed to initialize, disable"); - m_first_port_available = false; - configuration &= ~I8042ConfigurationFlag::FirstPS2PortInterrupt; - configuration |= I8042ConfigurationFlag::FirstPS2PortClock; - m_keyboard_device = nullptr; - SpinlockLocker lock(m_lock); - TRY(do_wait_then_write(I8042Port::Command, I8042Command::WriteConfiguration)); - TRY(do_wait_then_write(I8042Port::Buffer, configuration)); - } else { - m_keyboard_device = error_or_device.release_value(); - } - } - if (m_second_port_available) { - auto vmmouse_device_or_error = VMWareMouseDevice::try_to_initialize(*this); - if (vmmouse_device_or_error.is_error()) { - // FIXME: is there something to do with the VMWare errors? - auto mouse_device_or_error = PS2MouseDevice::try_to_initialize(*this); - if (mouse_device_or_error.is_error()) { - dbgln("I8042: Mouse device failed to initialize, disable"); - m_second_port_available = false; - configuration |= I8042ConfigurationFlag::SecondPS2PortClock; - m_mouse_device = nullptr; - SpinlockLocker lock(m_lock); - TRY(do_wait_then_write(I8042Port::Command, I8042Command::WriteConfiguration)); - TRY(do_wait_then_write(I8042Port::Buffer, configuration)); - } else { - m_mouse_device = mouse_device_or_error.release_value(); - } - } else { - m_mouse_device = vmmouse_device_or_error.release_value(); - } - } - - // Enable IRQs after both are detected and initialized - if (m_keyboard_device) - m_keyboard_device->enable_interrupts(); - if (m_mouse_device) - m_mouse_device->enable_interrupts(); - return {}; -} - -bool I8042Controller::irq_process_input_buffer(HIDDevice::Type instrument_type) -{ - VERIFY(Processor::current_in_irq()); - - u8 status = IO::in8(I8042Port::Status); - if (!(status & I8042StatusFlag::OutputBuffer)) - return false; - u8 byte = IO::in8(I8042Port::Buffer); - if (instrument_type == HIDDevice::Type::Mouse) { - VERIFY(m_mouse_device); - static_cast<PS2MouseDevice&>(*m_mouse_device).irq_handle_byte_read(byte); - return true; - } - if (instrument_type == HIDDevice::Type::Keyboard) { - VERIFY(m_keyboard_device); - static_cast<PS2KeyboardDevice&>(*m_keyboard_device).irq_handle_byte_read(byte); - return true; - } - return false; -} - -ErrorOr<void> I8042Controller::drain_output_buffer() -{ - for (int attempt = 0; attempt < 50; attempt++) { - u8 status = IO::in8(I8042Port::Status); - if (!(status & I8042StatusFlag::OutputBuffer)) - return {}; - IO::in8(I8042Port::Buffer); - - microseconds_delay(100); - } - return Error::from_errno(EBUSY); -} - -ErrorOr<void> I8042Controller::do_reset_device(HIDDevice::Type device) -{ - VERIFY(device != HIDDevice::Type::Unknown); - VERIFY(m_lock.is_locked()); - - VERIFY(!Processor::current_in_irq()); - auto reset_result = TRY(do_send_command(device, I8042Command::Reset)); - // FIXME: Is this the correct errno value for this? - if (reset_result != I8042Response::Acknowledge) - return Error::from_errno(EIO); - // Wait until we get the self-test result - auto self_test_result = TRY(do_wait_then_read(I8042Port::Buffer)); - - // FIXME: Is this the correct errno value for this? - if (self_test_result != I8042Response::Success) - return Error::from_errno(EIO); - return {}; -} - -ErrorOr<u8> I8042Controller::do_send_command(HIDDevice::Type device, u8 command) -{ - VERIFY(device != HIDDevice::Type::Unknown); - VERIFY(m_lock.is_locked()); - - VERIFY(!Processor::current_in_irq()); - - return do_write_to_device(device, command); -} - -ErrorOr<u8> I8042Controller::do_send_command(HIDDevice::Type device, u8 command, u8 data) -{ - VERIFY(device != HIDDevice::Type::Unknown); - VERIFY(m_lock.is_locked()); - - VERIFY(!Processor::current_in_irq()); - - u8 response = TRY(do_write_to_device(device, command)); - if (response == I8042Response::Acknowledge) - response = TRY(do_write_to_device(device, data)); - return response; -} - -ErrorOr<u8> I8042Controller::do_write_to_device(HIDDevice::Type device, u8 data) -{ - VERIFY(device != HIDDevice::Type::Unknown); - VERIFY(m_lock.is_locked()); - - VERIFY(!Processor::current_in_irq()); - - int attempts = 0; - u8 response; - do { - if (device != HIDDevice::Type::Keyboard) { - TRY(prepare_for_output()); - IO::out8(I8042Port::Command, I8042Command::WriteSecondPS2PortInputBuffer); - } - TRY(prepare_for_output()); - IO::out8(I8042Port::Buffer, data); - - response = TRY(do_wait_then_read(I8042Port::Buffer)); - } while (response == I8042Response::Resend && ++attempts < 250); - if (attempts >= 250) - dbgln("Failed to write byte to device, gave up"); - return response; -} - -ErrorOr<u8> I8042Controller::do_read_from_device(HIDDevice::Type device) -{ - VERIFY(device != HIDDevice::Type::Unknown); - - TRY(prepare_for_input(device)); - return IO::in8(I8042Port::Buffer); -} - -ErrorOr<void> I8042Controller::prepare_for_input(HIDDevice::Type device) -{ - VERIFY(m_lock.is_locked()); - u8 const second_port_flag = device == HIDDevice::Type::Keyboard ? 0 : I8042StatusFlag::SecondPS2PortOutputBuffer; - for (int attempt = 0; attempt < 1000; attempt++) { - u8 status = IO::in8(I8042Port::Status); - if (!(status & I8042StatusFlag::OutputBuffer)) { - microseconds_delay(1000); - continue; - } - if (device == HIDDevice::Type::Unknown) - return {}; - if ((status & I8042StatusFlag::SecondPS2PortOutputBuffer) == second_port_flag) - return {}; - microseconds_delay(1000); - } - return Error::from_errno(EBUSY); -} - -ErrorOr<void> I8042Controller::prepare_for_output() -{ - VERIFY(m_lock.is_locked()); - for (int attempt = 0; attempt < 250; attempt++) { - u8 status = IO::in8(I8042Port::Status); - if (!(status & I8042StatusFlag::InputBuffer)) - return {}; - microseconds_delay(1000); - } - return Error::from_errno(EBUSY); -} - -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); -} - -ErrorOr<void> I8042Controller::do_wait_then_write(u8 port, u8 data) -{ - VERIFY(m_lock.is_locked()); - TRY(prepare_for_output()); - IO::out8(port, data); - return {}; -} - -ErrorOr<u8> I8042Controller::do_wait_then_read(u8 port) -{ - VERIFY(m_lock.is_locked()); - TRY(prepare_for_input(HIDDevice::Type::Unknown)); - return IO::in8(port); -} - -} diff --git a/Kernel/Devices/HID/I8042Controller.h b/Kernel/Devices/HID/I8042Controller.h deleted file mode 100644 index 997cf4517d..0000000000 --- a/Kernel/Devices/HID/I8042Controller.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2020, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <AK/AtomicRefCounted.h> -#include <Kernel/Devices/HID/KeyboardDevice.h> -#include <Kernel/Devices/HID/MouseDevice.h> -#include <Kernel/Locking/Spinlock.h> - -namespace Kernel { - -enum I8042Port : u8 { - Buffer = 0x60, - Command = 0x64, - Status = 0x64, -}; - -enum I8042Command : u8 { - ReadConfiguration = 0x20, - WriteConfiguration = 0x60, - DisableSecondPS2Port = 0xA7, - EnableSecondPS2Port = 0xA8, - TestSecondPS2Port = 0xA9, - TestPS2Controller = 0xAA, - TestFirstPS2Port = 0xAB, - DisableFirstPS2Port = 0xAD, - EnableFirstPS2Port = 0xAE, - WriteSecondPS2PortInputBuffer = 0xD4, - SetScanCodeSet = 0xF0, - GetDeviceID = 0xF2, - SetSampleRate = 0xF3, - EnablePacketStreaming = 0xF4, - SetDefaults = 0xF6, - Reset = 0xFF, -}; - -enum I8042ConfigurationFlag : u8 { - FirstPS2PortInterrupt = 1 << 0, - SecondPS2PortInterrupt = 1 << 1, - SystemFlag = 1 << 2, - FirstPS2PortClock = 1 << 4, - SecondPS2PortClock = 1 << 5, - FirstPS2PortTranslation = 1 << 6, -}; - -enum I8042StatusFlag : u8 { - OutputBuffer = 1 << 0, - InputBuffer = 1 << 1, - System = 1 << 2, - InputType = 1 << 3, - SecondPS2PortOutputBuffer = 1 << 5, - TimeoutError = 1 << 6, - ParityError = 1 << 7, -}; - -enum I8042Response : u8 { - ControllerTestPassed = 0x55, - Success = 0xAA, - Acknowledge = 0xFA, - Resend = 0xFE, -}; - -class I8042Controller; -class I8042Device { -public: - virtual ~I8042Device() = default; - - virtual void irq_handle_byte_read(u8 byte) = 0; - -protected: - explicit I8042Device(I8042Controller const& ps2_controller) - : m_i8042_controller(ps2_controller) - { - } - - NonnullLockRefPtr<I8042Controller> m_i8042_controller; -}; - -class PS2KeyboardDevice; -class PS2MouseDevice; -class HIDManagement; -class I8042Controller final : public AtomicRefCounted<I8042Controller> { - friend class PS2KeyboardDevice; - friend class PS2MouseDevice; - -public: - static NonnullLockRefPtr<I8042Controller> initialize(); - - ErrorOr<void> detect_devices(); - - ErrorOr<void> reset_device(HIDDevice::Type device) - { - SpinlockLocker lock(m_lock); - return do_reset_device(device); - } - - ErrorOr<u8> send_command(HIDDevice::Type device, u8 command) - { - SpinlockLocker lock(m_lock); - return do_send_command(device, command); - } - ErrorOr<u8> send_command(HIDDevice::Type device, u8 command, u8 data) - { - SpinlockLocker lock(m_lock); - return do_send_command(device, command, data); - } - - ErrorOr<u8> read_from_device(HIDDevice::Type device) - { - SpinlockLocker lock(m_lock); - return do_read_from_device(device); - } - - ErrorOr<void> wait_then_write(u8 port, u8 data) - { - SpinlockLocker lock(m_lock); - return do_wait_then_write(port, data); - } - - ErrorOr<u8> wait_then_read(u8 port) - { - SpinlockLocker lock(m_lock); - return do_wait_then_read(port); - } - - ErrorOr<void> prepare_for_output(); - ErrorOr<void> prepare_for_input(HIDDevice::Type); - - bool irq_process_input_buffer(HIDDevice::Type); - - LockRefPtr<MouseDevice> mouse() const; - LockRefPtr<KeyboardDevice> keyboard() const; - - // Note: This function exists only for the initialization process of the controller - bool check_existence_via_probing(Badge<HIDManagement>); - -private: - I8042Controller(); - ErrorOr<void> do_reset_device(HIDDevice::Type); - ErrorOr<u8> do_send_command(HIDDevice::Type type, u8 data); - ErrorOr<u8> do_send_command(HIDDevice::Type device, u8 command, u8 data); - ErrorOr<u8> do_write_to_device(HIDDevice::Type device, u8 data); - ErrorOr<u8> do_read_from_device(HIDDevice::Type device); - ErrorOr<void> do_wait_then_write(u8 port, u8 data); - ErrorOr<u8> do_wait_then_read(u8 port); - ErrorOr<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); - - Spinlock m_lock { LockRank::None }; - bool m_first_port_available { false }; - bool m_second_port_available { false }; - bool m_is_dual_channel { false }; - LockRefPtr<MouseDevice> m_mouse_device; - LockRefPtr<KeyboardDevice> m_keyboard_device; -}; - -} diff --git a/Kernel/Devices/HID/PS2KeyboardDevice.cpp b/Kernel/Devices/HID/PS2KeyboardDevice.cpp deleted file mode 100644 index ba8a3a3b25..0000000000 --- a/Kernel/Devices/HID/PS2KeyboardDevice.cpp +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include <AK/Types.h> -#include <Kernel/Debug.h> -#include <Kernel/Devices/DeviceManagement.h> -#include <Kernel/Devices/HID/HIDManagement.h> -#include <Kernel/Devices/HID/PS2KeyboardDevice.h> -#include <Kernel/Scheduler.h> -#include <Kernel/Sections.h> -#include <Kernel/TTY/ConsoleManagement.h> -#include <Kernel/WorkQueue.h> - -namespace Kernel { - -#define IRQ_KEYBOARD 1 - -void PS2KeyboardDevice::irq_handle_byte_read(u8 byte) -{ - u8 ch = byte & 0x7f; - bool pressed = !(byte & 0x80); - - m_entropy_source.add_random_event(byte); - - if (byte == 0xe0) { - m_has_e0_prefix = true; - return; - } - - if ((m_modifiers == (Mod_Alt | Mod_Shift) || m_modifiers == (Mod_Ctrl | Mod_Alt | Mod_Shift)) && byte == 0x58) { - // 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)); - } - - dbgln_if(KEYBOARD_DEBUG, "Keyboard::irq_handle_byte_read: {:#02x} {}", ch, (pressed ? "down" : "up")); - switch (ch) { - case 0x38: - if (m_has_e0_prefix) - update_modifier(Mod_AltGr, pressed); - else - update_modifier(Mod_Alt, pressed); - break; - case 0x1d: - update_modifier(Mod_Ctrl, pressed); - break; - case 0x5b: - m_left_super_pressed = pressed; - update_modifier(Mod_Super, m_left_super_pressed || m_right_super_pressed); - break; - case 0x5c: - m_right_super_pressed = pressed; - update_modifier(Mod_Super, m_left_super_pressed || m_right_super_pressed); - break; - case 0x2a: - m_left_shift_pressed = pressed; - update_modifier(Mod_Shift, m_left_shift_pressed || m_right_shift_pressed); - break; - case 0x36: - m_right_shift_pressed = pressed; - update_modifier(Mod_Shift, m_left_shift_pressed || m_right_shift_pressed); - break; - } - switch (ch) { - case I8042Response::Acknowledge: - break; - default: - if ((m_modifiers & Mod_Alt) != 0 && ch >= 2 && ch <= 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([ch]() { - ConsoleManagement::the().switch_to(ch - 0x02); - })); - } - key_state_changed(ch, pressed); - } -} - -bool PS2KeyboardDevice::handle_irq(RegisterState const&) -{ - // The controller will read the data and call irq_handle_byte_read - // for the appropriate device - return m_i8042_controller->irq_process_input_buffer(HIDDevice::Type::Keyboard); -} - -UNMAP_AFTER_INIT ErrorOr<NonnullLockRefPtr<PS2KeyboardDevice>> PS2KeyboardDevice::try_to_initialize(I8042Controller const& ps2_controller) -{ - auto keyboard_device = TRY(DeviceManagement::try_create_device<PS2KeyboardDevice>(ps2_controller)); - - TRY(keyboard_device->initialize()); - - return keyboard_device; -} - -UNMAP_AFTER_INIT ErrorOr<void> PS2KeyboardDevice::initialize() -{ - return m_i8042_controller->reset_device(HIDDevice::Type::Keyboard); -} - -// FIXME: UNMAP_AFTER_INIT might not be correct, because in practice PS/2 devices -// are hot pluggable. -UNMAP_AFTER_INIT PS2KeyboardDevice::PS2KeyboardDevice(I8042Controller const& ps2_controller) - : IRQHandler(IRQ_KEYBOARD) - , KeyboardDevice() - , I8042Device(ps2_controller) -{ -} - -// FIXME: UNMAP_AFTER_INIT might not be correct, because in practice PS/2 devices -// are hot pluggable. -UNMAP_AFTER_INIT PS2KeyboardDevice::~PS2KeyboardDevice() = default; - -} diff --git a/Kernel/Devices/HID/PS2KeyboardDevice.h b/Kernel/Devices/HID/PS2KeyboardDevice.h deleted file mode 100644 index 24e9465eea..0000000000 --- a/Kernel/Devices/HID/PS2KeyboardDevice.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <AK/CircularQueue.h> -#include <AK/DoublyLinkedList.h> -#include <AK/Types.h> -#include <Kernel/API/KeyCode.h> -#include <Kernel/Devices/HID/I8042Controller.h> -#include <Kernel/Devices/HID/KeyboardDevice.h> -#include <Kernel/Interrupts/IRQHandler.h> -#include <Kernel/Random.h> - -namespace Kernel { - -class PS2KeyboardDevice final : public IRQHandler - , public KeyboardDevice - , public I8042Device { - friend class DeviceManagement; - -public: - static ErrorOr<NonnullLockRefPtr<PS2KeyboardDevice>> try_to_initialize(I8042Controller const&); - virtual ~PS2KeyboardDevice() override; - ErrorOr<void> initialize(); - - virtual StringView purpose() const override { return class_name(); } - - // ^I8042Device - virtual void irq_handle_byte_read(u8 byte) override; - virtual void enable_interrupts() override - { - enable_irq(); - } - -private: - explicit PS2KeyboardDevice(I8042Controller const&); - - // ^IRQHandler - virtual bool handle_irq(RegisterState const&) override; - - // ^CharacterDevice - virtual StringView class_name() const override { return "KeyboardDevice"sv; } -}; - -} diff --git a/Kernel/Devices/HID/PS2MouseDevice.cpp b/Kernel/Devices/HID/PS2MouseDevice.cpp deleted file mode 100644 index 86f090ffea..0000000000 --- a/Kernel/Devices/HID/PS2MouseDevice.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include <AK/Memory.h> -#include <Kernel/Arch/x86/Hypervisor/VMWareBackdoor.h> -#include <Kernel/Debug.h> -#include <Kernel/Devices/DeviceManagement.h> -#include <Kernel/Devices/HID/PS2MouseDevice.h> -#include <Kernel/Sections.h> - -namespace Kernel { - -#define IRQ_MOUSE 12 - -#define PS2MOUSE_INTELLIMOUSE_ID 0x03 -#define PS2MOUSE_INTELLIMOUSE_EXPLORER_ID 0x04 - -UNMAP_AFTER_INIT PS2MouseDevice::PS2MouseDevice(I8042Controller const& ps2_controller) - : IRQHandler(IRQ_MOUSE) - , MouseDevice() - , I8042Device(ps2_controller) -{ -} - -UNMAP_AFTER_INIT PS2MouseDevice::~PS2MouseDevice() = default; - -bool PS2MouseDevice::handle_irq(RegisterState const&) -{ - // The controller will read the data and call irq_handle_byte_read - // for the appropriate device - return m_i8042_controller->irq_process_input_buffer(instrument_type()); -} - -void PS2MouseDevice::irq_handle_byte_read(u8 byte) -{ - auto commit_packet = [&] { - m_data_state = 0; - dbgln_if(PS2MOUSE_DEBUG, "PS2Mouse: {}, {} {} {}", - m_data.bytes[1], - m_data.bytes[2], - (m_data.bytes[0] & 1) ? "Left" : "", - (m_data.bytes[0] & 2) ? "Right" : ""); - - m_entropy_source.add_random_event(m_data.dword); - - { - SpinlockLocker lock(m_queue_lock); - m_queue.enqueue(parse_data_packet(m_data)); - } - evaluate_block_conditions(); - }; - - VERIFY(m_data_state < sizeof(m_data.bytes) / sizeof(m_data.bytes[0])); - m_data.bytes[m_data_state] = byte; - - switch (m_data_state) { - case 0: - if (!(byte & 0x08)) { - dbgln("PS2Mouse: Stream out of sync."); - break; - } - ++m_data_state; - break; - case 1: - ++m_data_state; - break; - case 2: - if (m_has_wheel) { - ++m_data_state; - break; - } - commit_packet(); - break; - case 3: - VERIFY(m_has_wheel); - commit_packet(); - break; - } -} - -MousePacket PS2MouseDevice::parse_data_packet(RawPacket const& raw_packet) -{ - int x = raw_packet.bytes[1]; - int y = raw_packet.bytes[2]; - int z = 0; - int w = 0; - if (m_has_wheel) { - // FIXME: For non-Intellimouse, this is a full byte. - // However, for now, m_has_wheel is only set for Intellimouse. - z = (char)(raw_packet.bytes[3] & 0x0f); - - // -1 in 4 bits - if (z == 15) - z = -1; - - if ((raw_packet.bytes[3] & 0xc0) == 0x40) { - // FIXME: Scroll only functions correctly when the sign is flipped there - w = -z; - z = 0; - } else { - w = 0; - } - } - bool x_overflow = raw_packet.bytes[0] & 0x40; - bool y_overflow = raw_packet.bytes[0] & 0x80; - bool x_sign = raw_packet.bytes[0] & 0x10; - bool y_sign = raw_packet.bytes[0] & 0x20; - if (x && x_sign) - x -= 0x100; - if (y && y_sign) - y -= 0x100; - if (x_overflow || y_overflow) { - x = 0; - y = 0; - } - MousePacket packet; - packet.x = x; - packet.y = y; - packet.z = z; - packet.w = w; - packet.buttons = raw_packet.bytes[0] & 0x07; - - if (m_has_five_buttons) { - if (raw_packet.bytes[3] & 0x10) - packet.buttons |= MousePacket::BackwardButton; - if (raw_packet.bytes[3] & 0x20) - packet.buttons |= MousePacket::ForwardButton; - } - - packet.is_relative = true; - dbgln_if(PS2MOUSE_DEBUG, "PS2 Relative Mouse: Buttons {:x}", packet.buttons); - dbgln_if(PS2MOUSE_DEBUG, "Mouse: X {}, Y {}, Z {}, W {}", packet.x, packet.y, packet.z, packet.w); - return packet; -} - -ErrorOr<u8> PS2MouseDevice::get_device_id() -{ - TRY(send_command(I8042Command::GetDeviceID)); - return read_from_device(); -} - -ErrorOr<u8> PS2MouseDevice::read_from_device() -{ - return m_i8042_controller->read_from_device(instrument_type()); -} - -ErrorOr<u8> PS2MouseDevice::send_command(u8 command) -{ - u8 response = TRY(m_i8042_controller->send_command(instrument_type(), command)); - - if (response != I8042Response::Acknowledge) { - dbgln("PS2MouseDevice: Command {} got {} but expected ack: {}", command, response, static_cast<u8>(I8042Response::Acknowledge)); - return Error::from_errno(EIO); - } - return response; -} - -ErrorOr<u8> PS2MouseDevice::send_command(u8 command, u8 data) -{ - u8 response = TRY(m_i8042_controller->send_command(instrument_type(), command, data)); - if (response != I8042Response::Acknowledge) { - dbgln("PS2MouseDevice: Command {} got {} but expected ack: {}", command, response, static_cast<u8>(I8042Response::Acknowledge)); - return Error::from_errno(EIO); - } - return response; -} - -ErrorOr<void> PS2MouseDevice::set_sample_rate(u8 rate) -{ - TRY(send_command(I8042Command::SetSampleRate, rate)); - return {}; -} - -UNMAP_AFTER_INIT ErrorOr<NonnullLockRefPtr<PS2MouseDevice>> PS2MouseDevice::try_to_initialize(I8042Controller const& ps2_controller) -{ - auto mouse_device = TRY(DeviceManagement::try_create_device<PS2MouseDevice>(ps2_controller)); - TRY(mouse_device->initialize()); - return mouse_device; -} - -UNMAP_AFTER_INIT ErrorOr<void> PS2MouseDevice::initialize() -{ - TRY(m_i8042_controller->reset_device(instrument_type())); - - u8 device_id = TRY(read_from_device()); - - TRY(send_command(I8042Command::SetDefaults)); - - TRY(send_command(I8042Command::EnablePacketStreaming)); - - if (device_id != PS2MOUSE_INTELLIMOUSE_ID) { - // Send magical wheel initiation sequence. - TRY(set_sample_rate(200)); - TRY(set_sample_rate(100)); - TRY(set_sample_rate(80)); - device_id = TRY(get_device_id()); - } - if (device_id == PS2MOUSE_INTELLIMOUSE_ID) { - m_has_wheel = true; - dmesgln("PS2MouseDevice: Mouse wheel enabled!"); - } else { - dmesgln("PS2MouseDevice: No mouse wheel detected!"); - } - - if (device_id == PS2MOUSE_INTELLIMOUSE_ID) { - // Try to enable 5 buttons as well! - TRY(set_sample_rate(200)); - TRY(set_sample_rate(200)); - TRY(set_sample_rate(80)); - device_id = TRY(get_device_id()); - } - - if (device_id == PS2MOUSE_INTELLIMOUSE_EXPLORER_ID) { - m_has_five_buttons = true; - dmesgln("PS2MouseDevice: 5 buttons enabled!"); - } - return {}; -} - -} diff --git a/Kernel/Devices/HID/PS2MouseDevice.h b/Kernel/Devices/HID/PS2MouseDevice.h deleted file mode 100644 index 773d58bd4e..0000000000 --- a/Kernel/Devices/HID/PS2MouseDevice.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <AK/CircularQueue.h> -#include <Kernel/API/MousePacket.h> -#include <Kernel/Devices/HID/I8042Controller.h> -#include <Kernel/Devices/HID/MouseDevice.h> -#include <Kernel/Interrupts/IRQHandler.h> -#include <Kernel/Random.h> - -namespace Kernel { -class PS2MouseDevice : public IRQHandler - , public MouseDevice - , public I8042Device { - friend class DeviceManagement; - -public: - static ErrorOr<NonnullLockRefPtr<PS2MouseDevice>> try_to_initialize(I8042Controller const&); - ErrorOr<void> initialize(); - - virtual ~PS2MouseDevice() override; - - virtual StringView purpose() const override { return class_name(); } - - // ^I8042Device - virtual void irq_handle_byte_read(u8 byte) override; - virtual void enable_interrupts() override - { - enable_irq(); - } - -protected: - explicit PS2MouseDevice(I8042Controller const&); - - // ^IRQHandler - virtual bool handle_irq(RegisterState const&) override; - - struct RawPacket { - union { - u32 dword; - u8 bytes[4]; - }; - }; - - ErrorOr<u8> read_from_device(); - ErrorOr<u8> send_command(u8 command); - ErrorOr<u8> send_command(u8 command, u8 data); - MousePacket parse_data_packet(RawPacket const&); - ErrorOr<void> set_sample_rate(u8); - ErrorOr<u8> get_device_id(); - - u8 m_data_state { 0 }; - RawPacket m_data; - bool m_has_wheel { false }; - bool m_has_five_buttons { false }; -}; - -} diff --git a/Kernel/Devices/HID/VMWareMouseDevice.cpp b/Kernel/Devices/HID/VMWareMouseDevice.cpp deleted file mode 100644 index b059477338..0000000000 --- a/Kernel/Devices/HID/VMWareMouseDevice.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include <Kernel/Arch/x86/Hypervisor/VMWareBackdoor.h> -#include <Kernel/Devices/DeviceManagement.h> -#include <Kernel/Devices/HID/VMWareMouseDevice.h> -#include <Kernel/Sections.h> - -namespace Kernel { - -UNMAP_AFTER_INIT ErrorOr<NonnullLockRefPtr<VMWareMouseDevice>> VMWareMouseDevice::try_to_initialize(I8042Controller const& ps2_controller) -{ - // FIXME: return the correct error - if (!VMWareBackdoor::the()) - return Error::from_errno(EIO); - if (!VMWareBackdoor::the()->vmmouse_is_absolute()) - return Error::from_errno(EIO); - auto mouse_device = TRY(DeviceManagement::try_create_device<VMWareMouseDevice>(ps2_controller)); - TRY(mouse_device->initialize()); - return mouse_device; -} - -void VMWareMouseDevice::irq_handle_byte_read(u8) -{ - auto backdoor = VMWareBackdoor::the(); - VERIFY(backdoor); - VERIFY(backdoor->vmmouse_is_absolute()); - - // We will receive 4 bytes from the I8042 controller that we are going to - // ignore. Instead, we will check with VMWareBackdoor to see how many bytes - // of mouse event data are waiting for us. For each multiple of 4, we - // produce a mouse packet. - constexpr u8 max_iterations = 128; - u8 current_iteration = 0; - while (++current_iteration < max_iterations) { - auto number_of_mouse_event_bytes = backdoor->read_mouse_status_queue_size(); - if (number_of_mouse_event_bytes == 0) - break; - VERIFY(number_of_mouse_event_bytes % 4 == 0); - - auto mouse_packet = backdoor->receive_mouse_packet(); - m_entropy_source.add_random_event(mouse_packet); - { - SpinlockLocker lock(m_queue_lock); - m_queue.enqueue(mouse_packet); - } - } - evaluate_block_conditions(); -} - -VMWareMouseDevice::VMWareMouseDevice(I8042Controller const& ps2_controller) - : PS2MouseDevice(ps2_controller) -{ -} -VMWareMouseDevice::~VMWareMouseDevice() = default; - -} diff --git a/Kernel/Devices/HID/VMWareMouseDevice.h b/Kernel/Devices/HID/VMWareMouseDevice.h deleted file mode 100644 index 96e11f6923..0000000000 --- a/Kernel/Devices/HID/VMWareMouseDevice.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2021, Liav A. <liavalb@hotmail.co.il> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include <AK/CircularQueue.h> -#include <Kernel/API/MousePacket.h> -#include <Kernel/Devices/HID/I8042Controller.h> -#include <Kernel/Devices/HID/PS2MouseDevice.h> -#include <Kernel/Interrupts/IRQHandler.h> -#include <Kernel/Random.h> - -namespace Kernel { - -class VMWareMouseDevice final : public PS2MouseDevice { -public: - friend class DeviceManagement; - static ErrorOr<NonnullLockRefPtr<VMWareMouseDevice>> try_to_initialize(I8042Controller const&); - virtual ~VMWareMouseDevice() override; - - // ^I8042Device - virtual void irq_handle_byte_read(u8 byte) override; - -private: - explicit VMWareMouseDevice(I8042Controller const&); -}; - -} |