#pragma once #include #include #include #include #include namespace Kernel::ACPI { class EmbeddedController { public: static BAN::ErrorOr> create(AML::Scope&& scope, uint16_t command_port, uint16_t data_port, BAN::Optional gpe); ~EmbeddedController(); BAN::ErrorOr read_byte(uint8_t offset); BAN::ErrorOr write_byte(uint8_t offset, uint8_t value); const AML::Scope& scope() const { return m_scope; } private: EmbeddedController(AML::Scope&& scope, uint16_t command_port, uint16_t data_port, bool has_gpe) : m_scope(BAN::move(scope)) , m_command_port(command_port) , m_data_port(data_port) , m_has_gpe(has_gpe) { } private: void wait_status_bit(uint8_t bit, uint8_t value); uint8_t read_one(uint16_t port); void write_one(uint16_t port, uint8_t value); static void handle_gpe_wrapper(void*); void handle_gpe(); BAN::ErrorOr call_query_method(uint8_t notification); void thread_task(); struct Command { uint8_t command; BAN::Optional data1; BAN::Optional data2; uint8_t* response; BAN::Atomic done; }; BAN::ErrorOr send_command(Command& command); private: const AML::Scope m_scope; const uint16_t m_command_port; const uint16_t m_data_port; const bool m_has_gpe; Mutex m_mutex; ThreadBlocker m_thread_blocker; BAN::Optional m_queued_command; Thread* m_thread { nullptr }; }; }