/* * Copyright (c) 2020, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include 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) { } NonnullRefPtr m_i8042_controller; }; class PS2KeyboardDevice; class PS2MouseDevice; class HIDManagement; class I8042Controller : public RefCounted { friend class PS2KeyboardDevice; friend class PS2MouseDevice; public: static NonnullRefPtr initialize(); ErrorOr detect_devices(); ErrorOr reset_device(HIDDevice::Type device) { SpinlockLocker lock(m_lock); return do_reset_device(device); } ErrorOr send_command(HIDDevice::Type device, u8 command) { SpinlockLocker lock(m_lock); return do_send_command(device, command); } ErrorOr send_command(HIDDevice::Type device, u8 command, u8 data) { SpinlockLocker lock(m_lock); return do_send_command(device, command, data); } ErrorOr read_from_device(HIDDevice::Type device) { SpinlockLocker lock(m_lock); return do_read_from_device(device); } ErrorOr wait_then_write(u8 port, u8 data) { SpinlockLocker lock(m_lock); return do_wait_then_write(port, data); } ErrorOr wait_then_read(u8 port) { SpinlockLocker lock(m_lock); return do_wait_then_read(port); } ErrorOr prepare_for_output(); ErrorOr prepare_for_input(HIDDevice::Type); bool irq_process_input_buffer(HIDDevice::Type); RefPtr mouse() const; RefPtr keyboard() const; // Note: This function exists only for the initialization process of the controller bool check_existence_via_probing(Badge); private: I8042Controller(); ErrorOr do_reset_device(HIDDevice::Type); ErrorOr do_send_command(HIDDevice::Type type, u8 data); ErrorOr do_send_command(HIDDevice::Type device, u8 command, u8 data); ErrorOr do_write_to_device(HIDDevice::Type device, u8 data); ErrorOr do_read_from_device(HIDDevice::Type device); ErrorOr do_wait_then_write(u8 port, u8 data); ErrorOr do_wait_then_read(u8 port); ErrorOr 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; bool m_first_port_available { false }; bool m_second_port_available { false }; bool m_is_dual_channel { false }; RefPtr m_mouse_device; RefPtr m_keyboard_device; }; }