#pragma once #include #include #include #include #include namespace Kernel::Input { class PS2Device; class PS2Controller { public: static BAN::ErrorOr initialize(); static PS2Controller& get(); bool append_command_queue(PS2Device*, uint8_t command, uint8_t response_size); bool append_command_queue(PS2Device*, uint8_t command, uint8_t data, uint8_t response_size); void update_command_queue(); // Returns true, if byte is used as command, if returns false, byte is meant to device bool handle_command_byte(PS2Device*, uint8_t); private: PS2Controller() = default; BAN::ErrorOr initialize_impl(); BAN::ErrorOr initialize_device(uint8_t); BAN::ErrorOr read_byte(); BAN::ErrorOr send_byte(uint16_t port, uint8_t byte); BAN::ErrorOr send_command(PS2::Command command); BAN::ErrorOr send_command(PS2::Command command, uint8_t data); BAN::ErrorOr device_send_byte(uint8_t device_index, uint8_t byte); BAN::ErrorOr device_send_byte_and_wait_ack(uint8_t device_index, uint8_t byte); uint8_t get_device_index(PS2Device*) const; private: struct Command { enum class State : uint8_t { NotSent, Sending, WaitingAck, WaitingResponse, }; State state; uint8_t device_index; uint8_t out_data[2]; uint8_t out_count; uint8_t in_count; uint8_t send_index; }; private: BAN::RefPtr m_devices[2]; Mutex m_mutex; RecursiveSpinLock m_cmd_lock; BAN::CircularQueue m_command_queue; uint64_t m_command_send_time { 0 }; }; }