diff options
Diffstat (limited to 'Kernel/Arch/x86_64')
-rw-r--r-- | Kernel/Arch/x86_64/ISABus/HID/PS2KeyboardDevice.cpp | 77 | ||||
-rw-r--r-- | Kernel/Arch/x86_64/ISABus/HID/PS2KeyboardDevice.h | 18 | ||||
-rw-r--r-- | Kernel/Arch/x86_64/ISABus/HID/PS2MouseDevice.cpp | 38 | ||||
-rw-r--r-- | Kernel/Arch/x86_64/ISABus/HID/PS2MouseDevice.h | 15 | ||||
-rw-r--r-- | Kernel/Arch/x86_64/ISABus/HID/VMWareMouseDevice.cpp | 19 | ||||
-rw-r--r-- | Kernel/Arch/x86_64/ISABus/HID/VMWareMouseDevice.h | 6 | ||||
-rw-r--r-- | Kernel/Arch/x86_64/ISABus/I8042Controller.cpp | 89 | ||||
-rw-r--r-- | Kernel/Arch/x86_64/ISABus/I8042Controller.h | 63 |
8 files changed, 156 insertions, 169 deletions
diff --git a/Kernel/Arch/x86_64/ISABus/HID/PS2KeyboardDevice.cpp b/Kernel/Arch/x86_64/ISABus/HID/PS2KeyboardDevice.cpp index 1f7b3140b2..4b4ea60e7d 100644 --- a/Kernel/Arch/x86_64/ISABus/HID/PS2KeyboardDevice.cpp +++ b/Kernel/Arch/x86_64/ISABus/HID/PS2KeyboardDevice.cpp @@ -10,10 +10,8 @@ #include <Kernel/Debug.h> #include <Kernel/Devices/DeviceManagement.h> #include <Kernel/Devices/HID/Management.h> -#include <Kernel/Scheduler.h> +#include <Kernel/Devices/HID/ScanCodeEvent.h> #include <Kernel/Sections.h> -#include <Kernel/TTY/ConsoleManagement.h> -#include <Kernel/WorkQueue.h> namespace Kernel { @@ -23,89 +21,46 @@ 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)); - } + ScanCodeEvent event {}; + event.pressed = pressed; + event.e0_prefix = m_has_e0_prefix; + m_has_e0_prefix = false; 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); - } + event.scan_code_value = ch; + m_keyboard_device->handle_scan_code_input_event(event); } 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); + return m_i8042_controller->irq_process_input_buffer(instrument_type()); } -UNMAP_AFTER_INIT ErrorOr<NonnullLockRefPtr<PS2KeyboardDevice>> PS2KeyboardDevice::try_to_initialize(I8042Controller const& ps2_controller) +UNMAP_AFTER_INIT ErrorOr<NonnullOwnPtr<PS2KeyboardDevice>> PS2KeyboardDevice::try_to_initialize(I8042Controller const& ps2_controller, KeyboardDevice const& keyboard_device) { - auto keyboard_device = TRY(DeviceManagement::try_create_device<PS2KeyboardDevice>(ps2_controller)); - - TRY(keyboard_device->initialize()); - - return keyboard_device; + auto device = TRY(adopt_nonnull_own_or_enomem(new (nothrow) PS2KeyboardDevice(ps2_controller, keyboard_device))); + TRY(device->initialize()); + return device; } UNMAP_AFTER_INIT ErrorOr<void> PS2KeyboardDevice::initialize() { - return m_i8042_controller->reset_device(HIDDevice::Type::Keyboard); + return m_i8042_controller->reset_device(PS2Device::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) +UNMAP_AFTER_INIT PS2KeyboardDevice::PS2KeyboardDevice(I8042Controller const& ps2_controller, KeyboardDevice const& keyboard_device) : IRQHandler(IRQ_KEYBOARD) - , KeyboardDevice() - , I8042Device(ps2_controller) + , PS2Device(ps2_controller) + , m_keyboard_device(keyboard_device) { } diff --git a/Kernel/Arch/x86_64/ISABus/HID/PS2KeyboardDevice.h b/Kernel/Arch/x86_64/ISABus/HID/PS2KeyboardDevice.h index 7faedbe921..4c459f49c8 100644 --- a/Kernel/Arch/x86_64/ISABus/HID/PS2KeyboardDevice.h +++ b/Kernel/Arch/x86_64/ISABus/HID/PS2KeyboardDevice.h @@ -10,39 +10,39 @@ #include <AK/Types.h> #include <Kernel/API/KeyCode.h> #include <Kernel/Arch/x86_64/ISABus/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 { + , public PS2Device { friend class DeviceManagement; public: - static ErrorOr<NonnullLockRefPtr<PS2KeyboardDevice>> try_to_initialize(I8042Controller const&); + static ErrorOr<NonnullOwnPtr<PS2KeyboardDevice>> try_to_initialize(I8042Controller const&, KeyboardDevice const&); virtual ~PS2KeyboardDevice() override; ErrorOr<void> initialize(); - virtual StringView purpose() const override { return class_name(); } + virtual StringView purpose() const override { return "PS2KeyboardDevice"sv; } - // ^I8042Device + // ^PS2Device virtual void irq_handle_byte_read(u8 byte) override; virtual void enable_interrupts() override { enable_irq(); } + virtual Type instrument_type() const override { return Type::Keyboard; } private: - explicit PS2KeyboardDevice(I8042Controller const&); + PS2KeyboardDevice(I8042Controller const&, KeyboardDevice const&); // ^IRQHandler virtual bool handle_irq(RegisterState const&) override; - // ^CharacterDevice - virtual StringView class_name() const override { return "KeyboardDevice"sv; } + bool m_has_e0_prefix { false }; + + NonnullRefPtr<KeyboardDevice> const m_keyboard_device; }; } diff --git a/Kernel/Arch/x86_64/ISABus/HID/PS2MouseDevice.cpp b/Kernel/Arch/x86_64/ISABus/HID/PS2MouseDevice.cpp index a00f33948c..a646dfda36 100644 --- a/Kernel/Arch/x86_64/ISABus/HID/PS2MouseDevice.cpp +++ b/Kernel/Arch/x86_64/ISABus/HID/PS2MouseDevice.cpp @@ -17,10 +17,10 @@ namespace Kernel { #define PS2MOUSE_INTELLIMOUSE_ID 0x03 #define PS2MOUSE_INTELLIMOUSE_EXPLORER_ID 0x04 -UNMAP_AFTER_INIT PS2MouseDevice::PS2MouseDevice(I8042Controller const& ps2_controller) +UNMAP_AFTER_INIT PS2MouseDevice::PS2MouseDevice(I8042Controller const& ps2_controller, MouseDevice const& mouse_device) : IRQHandler(IRQ_MOUSE) - , MouseDevice() - , I8042Device(ps2_controller) + , PS2Device(ps2_controller) + , m_mouse_device(mouse_device) { } @@ -35,21 +35,14 @@ bool PS2MouseDevice::handle_irq(RegisterState const&) void PS2MouseDevice::irq_handle_byte_read(u8 byte) { - auto commit_packet = [&] { + auto commit_packet = [this]() { 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(); + m_mouse_device->handle_mouse_packet_input_event(parse_data_packet(m_data)); }; VERIFY(m_data_state < sizeof(m_data.bytes) / sizeof(m_data.bytes[0])); @@ -59,25 +52,26 @@ void PS2MouseDevice::irq_handle_byte_read(u8 byte) case 0: if (!(byte & 0x08)) { dbgln("PS2Mouse: Stream out of sync."); - break; + return; } ++m_data_state; - break; + return; case 1: ++m_data_state; - break; + return; case 2: if (m_has_wheel) { ++m_data_state; - break; + return; } commit_packet(); - break; + return; case 3: VERIFY(m_has_wheel); commit_packet(); - break; + return; } + VERIFY_NOT_REACHED(); } MousePacket PS2MouseDevice::parse_data_packet(RawPacket const& raw_packet) @@ -173,11 +167,11 @@ ErrorOr<void> PS2MouseDevice::set_sample_rate(u8 rate) return {}; } -UNMAP_AFTER_INIT ErrorOr<NonnullLockRefPtr<PS2MouseDevice>> PS2MouseDevice::try_to_initialize(I8042Controller const& ps2_controller) +UNMAP_AFTER_INIT ErrorOr<NonnullOwnPtr<PS2MouseDevice>> PS2MouseDevice::try_to_initialize(I8042Controller const& ps2_controller, MouseDevice const& mouse_device) { - auto mouse_device = TRY(DeviceManagement::try_create_device<PS2MouseDevice>(ps2_controller)); - TRY(mouse_device->initialize()); - return mouse_device; + auto device = TRY(adopt_nonnull_own_or_enomem(new (nothrow) PS2MouseDevice(ps2_controller, mouse_device))); + TRY(device->initialize()); + return device; } UNMAP_AFTER_INIT ErrorOr<void> PS2MouseDevice::initialize() diff --git a/Kernel/Arch/x86_64/ISABus/HID/PS2MouseDevice.h b/Kernel/Arch/x86_64/ISABus/HID/PS2MouseDevice.h index 177097f5f3..c77830bd60 100644 --- a/Kernel/Arch/x86_64/ISABus/HID/PS2MouseDevice.h +++ b/Kernel/Arch/x86_64/ISABus/HID/PS2MouseDevice.h @@ -9,33 +9,32 @@ #include <AK/CircularQueue.h> #include <Kernel/API/MousePacket.h> #include <Kernel/Arch/x86_64/ISABus/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 { + , public PS2Device { friend class DeviceManagement; public: - static ErrorOr<NonnullLockRefPtr<PS2MouseDevice>> try_to_initialize(I8042Controller const&); + static ErrorOr<NonnullOwnPtr<PS2MouseDevice>> try_to_initialize(I8042Controller const&, MouseDevice const&); ErrorOr<void> initialize(); virtual ~PS2MouseDevice() override; - virtual StringView purpose() const override { return class_name(); } + virtual StringView purpose() const override { return "PS2MouseDevice"sv; } - // ^I8042Device + // ^PS2Device virtual void irq_handle_byte_read(u8 byte) override; virtual void enable_interrupts() override { enable_irq(); } + virtual Type instrument_type() const override { return Type::Mouse; } protected: - explicit PS2MouseDevice(I8042Controller const&); + PS2MouseDevice(I8042Controller const&, MouseDevice const&); // ^IRQHandler virtual bool handle_irq(RegisterState const&) override; @@ -58,6 +57,8 @@ protected: RawPacket m_data; bool m_has_wheel { false }; bool m_has_five_buttons { false }; + + NonnullRefPtr<MouseDevice> const m_mouse_device; }; } diff --git a/Kernel/Arch/x86_64/ISABus/HID/VMWareMouseDevice.cpp b/Kernel/Arch/x86_64/ISABus/HID/VMWareMouseDevice.cpp index ec6029b5b0..7bc88266c0 100644 --- a/Kernel/Arch/x86_64/ISABus/HID/VMWareMouseDevice.cpp +++ b/Kernel/Arch/x86_64/ISABus/HID/VMWareMouseDevice.cpp @@ -11,16 +11,16 @@ namespace Kernel { -UNMAP_AFTER_INIT ErrorOr<NonnullLockRefPtr<VMWareMouseDevice>> VMWareMouseDevice::try_to_initialize(I8042Controller const& ps2_controller) +UNMAP_AFTER_INIT ErrorOr<NonnullOwnPtr<VMWareMouseDevice>> VMWareMouseDevice::try_to_initialize(I8042Controller const& ps2_controller, MouseDevice const& mouse_device) { // 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; + auto device = TRY(adopt_nonnull_own_or_enomem(new (nothrow) VMWareMouseDevice(ps2_controller, mouse_device))); + TRY(device->initialize()); + return device; } void VMWareMouseDevice::irq_handle_byte_read(u8) @@ -42,17 +42,12 @@ void VMWareMouseDevice::irq_handle_byte_read(u8) 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); - } + m_mouse_device->handle_mouse_packet_input_event(mouse_packet); } - evaluate_block_conditions(); } -VMWareMouseDevice::VMWareMouseDevice(I8042Controller const& ps2_controller) - : PS2MouseDevice(ps2_controller) +VMWareMouseDevice::VMWareMouseDevice(I8042Controller const& ps2_controller, MouseDevice const& mouse_device) + : PS2MouseDevice(ps2_controller, mouse_device) { } VMWareMouseDevice::~VMWareMouseDevice() = default; diff --git a/Kernel/Arch/x86_64/ISABus/HID/VMWareMouseDevice.h b/Kernel/Arch/x86_64/ISABus/HID/VMWareMouseDevice.h index b0d753cc78..34104b447b 100644 --- a/Kernel/Arch/x86_64/ISABus/HID/VMWareMouseDevice.h +++ b/Kernel/Arch/x86_64/ISABus/HID/VMWareMouseDevice.h @@ -18,14 +18,14 @@ namespace Kernel { class VMWareMouseDevice final : public PS2MouseDevice { public: friend class DeviceManagement; - static ErrorOr<NonnullLockRefPtr<VMWareMouseDevice>> try_to_initialize(I8042Controller const&); + static ErrorOr<NonnullOwnPtr<VMWareMouseDevice>> try_to_initialize(I8042Controller const&, MouseDevice const&); virtual ~VMWareMouseDevice() override; - // ^I8042Device + // ^PS2Device virtual void irq_handle_byte_read(u8 byte) override; private: - explicit VMWareMouseDevice(I8042Controller const&); + VMWareMouseDevice(I8042Controller const&, MouseDevice const&); }; } diff --git a/Kernel/Arch/x86_64/ISABus/I8042Controller.cpp b/Kernel/Arch/x86_64/ISABus/I8042Controller.cpp index e593c19b87..57f7a86798 100644 --- a/Kernel/Arch/x86_64/ISABus/I8042Controller.cpp +++ b/Kernel/Arch/x86_64/ISABus/I8042Controller.cpp @@ -159,55 +159,63 @@ UNMAP_AFTER_INIT ErrorOr<void> I8042Controller::detect_devices() // Try to detect and initialize the devices if (m_first_port_available) { - auto error_or_device = PS2KeyboardDevice::try_to_initialize(*this); + // FIXME: Actually figure out the connected PS2 device type + m_first_ps2_port.device_type = PS2Device::Type::Keyboard; + auto keyboard_device = TRY(KeyboardDevice::try_to_initialize()); + auto error_or_device = PS2KeyboardDevice::try_to_initialize(*this, *keyboard_device); 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; + m_first_ps2_port.device = nullptr; + m_first_ps2_port.device_type = {}; SpinlockLocker lock(m_lock); // NOTE: Before setting the actual scan code set, stop packet streaming entirely. - TRY(send_command(HIDDevice::Type::Keyboard, I8042Command::DisablePacketStreaming)); + TRY(send_command(PS2Device::Type::Keyboard, I8042Command::DisablePacketStreaming)); TRY(do_wait_then_write(I8042Port::Buffer, I8042Command::SetScanCodeSet)); TRY(do_wait_then_write(I8042Port::Buffer, 0x2)); 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(); + m_first_ps2_port.device = error_or_device.release_value(); } } if (m_second_port_available) { - auto vmmouse_device_or_error = VMWareMouseDevice::try_to_initialize(*this); + // FIXME: Actually figure out the connected PS2 device type + m_second_ps2_port.device_type = PS2Device::Type::Mouse; + auto mouse_device = TRY(MouseDevice::try_to_initialize()); + auto vmmouse_device_or_error = VMWareMouseDevice::try_to_initialize(*this, *mouse_device); 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); + auto mouse_device_or_error = PS2MouseDevice::try_to_initialize(*this, *mouse_device); 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; + m_second_ps2_port.device = nullptr; + m_second_ps2_port.device_type = {}; 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(); + m_second_ps2_port.device = mouse_device_or_error.release_value(); } } else { - m_mouse_device = vmmouse_device_or_error.release_value(); + m_second_ps2_port.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(); + if (m_first_ps2_port.device) + m_first_ps2_port.device->enable_interrupts(); + if (m_second_ps2_port.device) + m_second_ps2_port.device->enable_interrupts(); return {}; } -bool I8042Controller::irq_process_input_buffer(HIDDevice::Type instrument_type) +bool I8042Controller::irq_process_input_buffer(PS2Device::Type instrument_type) { VERIFY(Processor::current_in_irq()); @@ -215,17 +223,20 @@ bool I8042Controller::irq_process_input_buffer(HIDDevice::Type instrument_type) 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; + + PS2Port* selected_port = nullptr; + if (m_first_ps2_port.device_type.has_value() && m_first_ps2_port.device_type.value() == instrument_type) { + VERIFY(m_first_ps2_port.device); + selected_port = &m_first_ps2_port; + } else if (m_second_ps2_port.device_type.has_value() && m_second_ps2_port.device_type.value() == instrument_type) { + VERIFY(m_second_ps2_port.device); + selected_port = &m_second_ps2_port; + } else { + return false; } - return false; + + selected_port->device->irq_handle_byte_read(byte); + return true; } ErrorOr<void> I8042Controller::drain_output_buffer() @@ -241,9 +252,9 @@ ErrorOr<void> I8042Controller::drain_output_buffer() return Error::from_errno(EBUSY); } -ErrorOr<void> I8042Controller::do_reset_device(HIDDevice::Type device) +ErrorOr<void> I8042Controller::do_reset_device(PS2Device::Type device) { - VERIFY(device != HIDDevice::Type::Unknown); + VERIFY(device != PS2Device::Type::Unknown); VERIFY(m_lock.is_locked()); VERIFY(!Processor::current_in_irq()); @@ -260,9 +271,9 @@ ErrorOr<void> I8042Controller::do_reset_device(HIDDevice::Type device) return {}; } -ErrorOr<u8> I8042Controller::do_send_command(HIDDevice::Type device, u8 command) +ErrorOr<u8> I8042Controller::do_send_command(PS2Device::Type device, u8 command) { - VERIFY(device != HIDDevice::Type::Unknown); + VERIFY(device != PS2Device::Type::Unknown); VERIFY(m_lock.is_locked()); VERIFY(!Processor::current_in_irq()); @@ -270,9 +281,9 @@ ErrorOr<u8> I8042Controller::do_send_command(HIDDevice::Type device, u8 command) return do_write_to_device(device, command); } -ErrorOr<u8> I8042Controller::do_send_command(HIDDevice::Type device, u8 command, u8 data) +ErrorOr<u8> I8042Controller::do_send_command(PS2Device::Type device, u8 command, u8 data) { - VERIFY(device != HIDDevice::Type::Unknown); + VERIFY(device != PS2Device::Type::Unknown); VERIFY(m_lock.is_locked()); VERIFY(!Processor::current_in_irq()); @@ -283,9 +294,9 @@ ErrorOr<u8> I8042Controller::do_send_command(HIDDevice::Type device, u8 command, return response; } -ErrorOr<u8> I8042Controller::do_write_to_device(HIDDevice::Type device, u8 data) +ErrorOr<u8> I8042Controller::do_write_to_device(PS2Device::Type device, u8 data) { - VERIFY(device != HIDDevice::Type::Unknown); + VERIFY(device != PS2Device::Type::Unknown); VERIFY(m_lock.is_locked()); VERIFY(!Processor::current_in_irq()); @@ -293,7 +304,7 @@ ErrorOr<u8> I8042Controller::do_write_to_device(HIDDevice::Type device, u8 data) int attempts = 0; u8 response; do { - if (device != HIDDevice::Type::Keyboard) { + if (device != PS2Device::Type::Keyboard) { TRY(prepare_for_output()); IO::out8(I8042Port::Command, I8042Command::WriteSecondPS2PortInputBuffer); } @@ -307,25 +318,25 @@ ErrorOr<u8> I8042Controller::do_write_to_device(HIDDevice::Type device, u8 data) return response; } -ErrorOr<u8> I8042Controller::do_read_from_device(HIDDevice::Type device) +ErrorOr<u8> I8042Controller::do_read_from_device(PS2Device::Type device) { - VERIFY(device != HIDDevice::Type::Unknown); + VERIFY(device != PS2Device::Type::Unknown); TRY(prepare_for_input(device)); return IO::in8(I8042Port::Buffer); } -ErrorOr<void> I8042Controller::prepare_for_input(HIDDevice::Type device) +ErrorOr<void> I8042Controller::prepare_for_input(PS2Device::Type device) { VERIFY(m_lock.is_locked()); - u8 const second_port_flag = device == HIDDevice::Type::Keyboard ? 0 : I8042StatusFlag::SecondPS2PortOutputBuffer; + u8 const second_port_flag = device == PS2Device::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) + if (device == PS2Device::Type::Unknown) return {}; if ((status & I8042StatusFlag::SecondPS2PortOutputBuffer) == second_port_flag) return {}; @@ -369,7 +380,7 @@ ErrorOr<void> I8042Controller::do_wait_then_write(u8 port, u8 data) ErrorOr<u8> I8042Controller::do_wait_then_read(u8 port) { VERIFY(m_lock.is_locked()); - TRY(prepare_for_input(HIDDevice::Type::Unknown)); + TRY(prepare_for_input(PS2Device::Type::Unknown)); return IO::in8(port); } diff --git a/Kernel/Arch/x86_64/ISABus/I8042Controller.h b/Kernel/Arch/x86_64/ISABus/I8042Controller.h index e04a5ba4b6..f663a43c53 100644 --- a/Kernel/Arch/x86_64/ISABus/I8042Controller.h +++ b/Kernel/Arch/x86_64/ISABus/I8042Controller.h @@ -10,6 +10,7 @@ #include <Kernel/Devices/HID/Controller.h> #include <Kernel/Devices/HID/KeyboardDevice.h> #include <Kernel/Devices/HID/MouseDevice.h> +#include <Kernel/Devices/HID/ScanCodeEvent.h> #include <Kernel/Locking/Spinlock.h> namespace Kernel { @@ -69,15 +70,23 @@ enum I8042Response : u8 { class I8042Controller; class PS2KeyboardDevice; class PS2MouseDevice; -class I8042Device { +class PS2Device { public: - virtual ~I8042Device() = default; + virtual ~PS2Device() = default; virtual void irq_handle_byte_read(u8 byte) = 0; virtual void enable_interrupts() = 0; + enum class Type { + Unknown = 0, + Keyboard, + Mouse, + }; + + virtual Type instrument_type() const = 0; + protected: - explicit I8042Device(I8042Controller const& ps2_controller) + explicit PS2Device(I8042Controller const& ps2_controller) : m_i8042_controller(ps2_controller) { } @@ -97,24 +106,24 @@ public: ErrorOr<void> detect_devices(); - ErrorOr<void> reset_device(HIDDevice::Type device) + ErrorOr<void> reset_device(PS2Device::Type device) { SpinlockLocker lock(m_lock); return do_reset_device(device); } - ErrorOr<u8> send_command(HIDDevice::Type device, u8 command) + ErrorOr<u8> send_command(PS2Device::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) + ErrorOr<u8> send_command(PS2Device::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) + ErrorOr<u8> read_from_device(PS2Device::Type device) { SpinlockLocker lock(m_lock); return do_read_from_device(device); @@ -133,20 +142,20 @@ public: } ErrorOr<void> prepare_for_output(); - ErrorOr<void> prepare_for_input(HIDDevice::Type); + ErrorOr<void> prepare_for_input(PS2Device::Type); - bool irq_process_input_buffer(HIDDevice::Type); + bool irq_process_input_buffer(PS2Device::Type); // 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_reset_device(PS2Device::Type); + ErrorOr<u8> do_send_command(PS2Device::Type type, u8 data); + ErrorOr<u8> do_send_command(PS2Device::Type device, u8 command, u8 data); + ErrorOr<u8> do_write_to_device(PS2Device::Type device, u8 data); + ErrorOr<u8> do_read_from_device(PS2Device::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(); @@ -159,8 +168,30 @@ private: bool m_first_port_available { false }; bool m_second_port_available { false }; bool m_is_dual_channel { false }; - LockRefPtr<PS2MouseDevice> m_mouse_device; - LockRefPtr<PS2KeyboardDevice> m_keyboard_device; + + // NOTE: Each i8042 controller can have at most 2 ports - a regular (traditional + // ATKBD) port and AUX port (for mouse devices mostly). + // However, the specification for i8042 controller, as well as decent hardware + // implementations and software drivers actually allow a user to still operate + // a keyboard and mouse even if they were connected in reverse (i.e. keyboard + // was connected to AUX port, and mouse was connected to the traditional ATKBD port). + // + // Please note, that if the keyboard and mouse devices are connected in reverse, then ATKBD translation mode + // cannot be sanely enabled due to obvious peripheral devices' protocol differences, and will result + // in misproper data being sent back. + struct PS2Port { + OwnPtr<PS2Device> device; + // NOTE: This value is being used as 1:1 map between the I8042 port being handled, to + // the either the MouseDevice or KeyboardDevice being attached. + Optional<PS2Device::Type> device_type; + }; + + // NOTE: Each i8042 controller can have at most 2 devices - a mouse and keyboard, + // mouse and a mouse, or keyboard and a keyboard. + // NOTE: This is usually used as the ATKBD port. + PS2Port m_first_ps2_port; + // NOTE: This is usually used as the AUX port. + PS2Port m_second_ps2_port; }; } |