Kernel: Move PS/2 command queue to controller instead of device
This commit is contained in:
		
							parent
							
								
									e8f853a197
								
							
						
					
					
						commit
						e4f48cbc73
					
				|  | @ -1,5 +1,6 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <BAN/CircularQueue.h> | ||||||
| #include <BAN/UniqPtr.h> | #include <BAN/UniqPtr.h> | ||||||
| #include <kernel/Device/Device.h> | #include <kernel/Device/Device.h> | ||||||
| #include <kernel/Input/PS2/Config.h> | #include <kernel/Input/PS2/Config.h> | ||||||
|  | @ -17,19 +18,17 @@ namespace Kernel::Input | ||||||
| 		static BAN::ErrorOr<void> initialize(); | 		static BAN::ErrorOr<void> initialize(); | ||||||
| 		static PS2Controller& get(); | 		static PS2Controller& get(); | ||||||
| 
 | 
 | ||||||
| 		BAN::ErrorOr<void> device_send_byte(PS2Device* device, uint8_t byte); | 		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); | ||||||
| 		[[nodiscard]] bool lock_command(PS2Device*); | 		void update_command_queue(); | ||||||
| 		void unlock_command(PS2Device*); | 		// Returns true, if byte is used as command, if returns false, byte is meant to device
 | ||||||
|  | 		bool handle_command_byte(PS2Device*, uint8_t); | ||||||
| 
 | 
 | ||||||
| 	private: | 	private: | ||||||
| 		PS2Controller() = default; | 		PS2Controller() = default; | ||||||
| 		BAN::ErrorOr<void> initialize_impl(); | 		BAN::ErrorOr<void> initialize_impl(); | ||||||
| 		BAN::ErrorOr<void> initialize_device(uint8_t); | 		BAN::ErrorOr<void> initialize_device(uint8_t); | ||||||
| 
 | 
 | ||||||
| 		BAN::ErrorOr<void> reset_device(uint8_t); |  | ||||||
| 		BAN::ErrorOr<void> set_scanning(uint8_t, bool); |  | ||||||
| 
 |  | ||||||
| 		BAN::ErrorOr<uint8_t> read_byte(); | 		BAN::ErrorOr<uint8_t> read_byte(); | ||||||
| 		BAN::ErrorOr<void> send_byte(uint16_t port, uint8_t byte); | 		BAN::ErrorOr<void> send_byte(uint16_t port, uint8_t byte); | ||||||
| 
 | 
 | ||||||
|  | @ -37,14 +36,31 @@ namespace Kernel::Input | ||||||
| 		BAN::ErrorOr<void> send_command(PS2::Command command, uint8_t data); | 		BAN::ErrorOr<void> send_command(PS2::Command command, uint8_t data); | ||||||
| 
 | 
 | ||||||
| 		BAN::ErrorOr<void> device_send_byte(uint8_t device_index, uint8_t byte); | 		BAN::ErrorOr<void> device_send_byte(uint8_t device_index, uint8_t byte); | ||||||
| 		BAN::ErrorOr<void> device_read_ack(uint8_t device_index); | 		BAN::ErrorOr<void> device_send_byte_and_wait_ack(uint8_t device_index, uint8_t byte); | ||||||
|  | 
 | ||||||
|  | 	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: | 	private: | ||||||
| 		BAN::RefPtr<PS2Device> m_devices[2]; | 		BAN::RefPtr<PS2Device> m_devices[2]; | ||||||
| 		RecursiveSpinLock m_lock; | 		RecursiveSpinLock m_lock; | ||||||
| 
 | 
 | ||||||
| 		PS2Device* m_executing_device	{ nullptr }; | 		BAN::CircularQueue<Command, 128> m_command_queue; | ||||||
| 		PS2Device* m_pending_device		{ nullptr }; |  | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,6 +1,5 @@ | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <BAN/CircularQueue.h> |  | ||||||
| #include <kernel/Input/PS2/Controller.h> | #include <kernel/Input/PS2/Controller.h> | ||||||
| #include <kernel/InterruptController.h> | #include <kernel/InterruptController.h> | ||||||
| 
 | 
 | ||||||
|  | @ -20,39 +19,16 @@ namespace Kernel::Input | ||||||
| 		virtual void handle_irq() final override; | 		virtual void handle_irq() final override; | ||||||
| 
 | 
 | ||||||
| 		virtual void handle_byte(uint8_t) = 0; | 		virtual void handle_byte(uint8_t) = 0; | ||||||
| 		virtual void handle_device_command_response(uint8_t) = 0; |  | ||||||
| 
 | 
 | ||||||
| 		virtual BAN::StringView name() const final override { return m_name; } | 		virtual BAN::StringView name() const final override { return m_name; } | ||||||
| 		virtual dev_t rdev() const final override { return m_rdev; } | 		virtual dev_t rdev() const final override { return m_rdev; } | ||||||
| 
 | 
 | ||||||
| 	private: | 		virtual void update() final override { m_controller.update_command_queue(); } | ||||||
| 		void update_command(); |  | ||||||
| 
 |  | ||||||
| 	private: |  | ||||||
| 		enum class State |  | ||||||
| 		{ |  | ||||||
| 			Normal, |  | ||||||
| 			WaitingAck, |  | ||||||
| 			WaitingResponse, |  | ||||||
| 		}; |  | ||||||
| 
 |  | ||||||
| 		struct Command |  | ||||||
| 		{ |  | ||||||
| 			uint8_t out_data[2]; |  | ||||||
| 			uint8_t out_count; |  | ||||||
| 			uint8_t in_count; |  | ||||||
| 			uint8_t send_index; |  | ||||||
| 		}; |  | ||||||
| 
 | 
 | ||||||
| 	private: | 	private: | ||||||
| 		const BAN::String m_name; | 		const BAN::String m_name; | ||||||
| 		const dev_t m_rdev; | 		const dev_t m_rdev; | ||||||
| 
 | 		PS2Controller& m_controller; | ||||||
| 		PS2Controller&					m_controller; |  | ||||||
| 		State							m_state			= State::Normal; |  | ||||||
| 		BAN::CircularQueue<Command, 10>	m_command_queue; |  | ||||||
| 
 |  | ||||||
| 		friend class PS2Controller; |  | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -22,7 +22,6 @@ namespace Kernel::Input | ||||||
| 		virtual void send_initialize() override; | 		virtual void send_initialize() override; | ||||||
| 
 | 
 | ||||||
| 		virtual void handle_byte(uint8_t) final override; | 		virtual void handle_byte(uint8_t) final override; | ||||||
| 		virtual void handle_device_command_response(uint8_t) final override; |  | ||||||
| 
 | 
 | ||||||
| 	private: | 	private: | ||||||
| 		PS2Keyboard(PS2Controller& controller); | 		PS2Keyboard(PS2Controller& controller); | ||||||
|  |  | ||||||
|  | @ -20,7 +20,6 @@ namespace Kernel::Input | ||||||
| 		virtual void send_initialize() override; | 		virtual void send_initialize() override; | ||||||
| 
 | 
 | ||||||
| 		virtual void handle_byte(uint8_t) final override; | 		virtual void handle_byte(uint8_t) final override; | ||||||
| 		virtual void handle_device_command_response(uint8_t) final override; |  | ||||||
| 
 | 
 | ||||||
| 	private: | 	private: | ||||||
| 		PS2Mouse(PS2Controller& controller); | 		PS2Mouse(PS2Controller& controller); | ||||||
|  |  | ||||||
|  | @ -21,6 +21,7 @@ namespace Kernel::Input | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<void> PS2Controller::send_byte(uint16_t port, uint8_t byte) | 	BAN::ErrorOr<void> PS2Controller::send_byte(uint16_t port, uint8_t byte) | ||||||
| 	{ | 	{ | ||||||
|  | 		ASSERT(interrupts_enabled()); | ||||||
| 		LockGuard _(m_lock); | 		LockGuard _(m_lock); | ||||||
| 		uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ps2_timeout_ms; | 		uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ps2_timeout_ms; | ||||||
| 		while (SystemTimer::get().ms_since_boot() < timeout) | 		while (SystemTimer::get().ms_since_boot() < timeout) | ||||||
|  | @ -35,6 +36,7 @@ namespace Kernel::Input | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<uint8_t> PS2Controller::read_byte() | 	BAN::ErrorOr<uint8_t> PS2Controller::read_byte() | ||||||
| 	{ | 	{ | ||||||
|  | 		ASSERT(interrupts_enabled()); | ||||||
| 		LockGuard _(m_lock); | 		LockGuard _(m_lock); | ||||||
| 		uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ps2_timeout_ms; | 		uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ps2_timeout_ms; | ||||||
| 		while (SystemTimer::get().ms_since_boot() < timeout) | 		while (SystemTimer::get().ms_since_boot() < timeout) | ||||||
|  | @ -61,31 +63,6 @@ namespace Kernel::Input | ||||||
| 		return {}; | 		return {}; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool PS2Controller::lock_command(PS2Device* device) |  | ||||||
| 	{ |  | ||||||
| 		if (m_executing_device && m_executing_device != device) |  | ||||||
| 		{ |  | ||||||
| 			ASSERT(!m_pending_device || m_pending_device == device); |  | ||||||
| 			m_pending_device = device; |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		m_executing_device = device; |  | ||||||
| 		return true; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	void PS2Controller::unlock_command(PS2Device* device) |  | ||||||
| 	{ |  | ||||||
| 		ASSERT(m_executing_device == device); |  | ||||||
| 		m_executing_device = nullptr; |  | ||||||
| 		if (m_pending_device) |  | ||||||
| 		{ |  | ||||||
| 			m_executing_device = m_pending_device; |  | ||||||
| 			m_pending_device = nullptr; |  | ||||||
| 			m_executing_device->update_command(); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	BAN::ErrorOr<void> PS2Controller::device_send_byte(uint8_t device_index, uint8_t byte) | 	BAN::ErrorOr<void> PS2Controller::device_send_byte(uint8_t device_index, uint8_t byte) | ||||||
| 	{ | 	{ | ||||||
| 		LockGuard _(m_lock); | 		LockGuard _(m_lock); | ||||||
|  | @ -95,25 +72,141 @@ namespace Kernel::Input | ||||||
| 		return {}; | 		return {}; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<void> PS2Controller::device_send_byte(PS2Device* device, uint8_t byte) | 	BAN::ErrorOr<void> PS2Controller::device_send_byte_and_wait_ack(uint8_t device_index, uint8_t byte) | ||||||
| 	{ |  | ||||||
| 		ASSERT(device); |  | ||||||
| 		ASSERT(device == m_devices[0].ptr() || device == m_devices[1].ptr()); |  | ||||||
| 		TRY(device_send_byte(device == m_devices[0].ptr() ? 0 : 1, byte)); |  | ||||||
| 		return {}; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	BAN::ErrorOr<void> PS2Controller::device_read_ack(uint8_t device_index) |  | ||||||
| 	{ | 	{ | ||||||
| 		LockGuard _(m_lock); | 		LockGuard _(m_lock); | ||||||
| 		if (TRY(read_byte()) != PS2::Response::ACK) | 		for (;;) | ||||||
| 		{ | 		{ | ||||||
| 			dwarnln_if(DEBUG_PS2, "PS/2 device on port {} did not respond with expected ACK", device_index); | 			TRY(device_send_byte(device_index, byte)); | ||||||
|  | 			uint8_t response = TRY(read_byte()); | ||||||
|  | 			if (response == PS2::Response::RESEND) | ||||||
|  | 				continue; | ||||||
|  | 			if (response == PS2::Response::ACK) | ||||||
|  | 				break; | ||||||
|  | 			dwarnln_if(DEBUG_PS2, "PS/2 device on port {} did not respond with expected ACK, got {2H}", device_index, byte); | ||||||
| 			return BAN::Error::from_errno(EBADMSG); | 			return BAN::Error::from_errno(EBADMSG); | ||||||
| 		} | 		} | ||||||
| 		return {}; | 		return {}; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	bool PS2Controller::append_command_queue(PS2Device* device, uint8_t command, uint8_t response_size) | ||||||
|  | 	{ | ||||||
|  | 		// NOTE: command queue push/pop must be done without interrupts
 | ||||||
|  | 		CriticalScope _; | ||||||
|  | 		ASSERT(device && (device == m_devices[0].ptr() || device == m_devices[1].ptr())); | ||||||
|  | 		if (m_command_queue.size() + 1 >= m_command_queue.capacity()) | ||||||
|  | 		{ | ||||||
|  | 			dprintln("PS/2 command queue full"); | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		m_command_queue.push(Command { | ||||||
|  | 			.state			= Command::State::NotSent, | ||||||
|  | 			.device_index	= (device == m_devices[0].ptr()) ? uint8_t(0) : uint8_t(1), | ||||||
|  | 			.out_data		= { command, 0x00 }, | ||||||
|  | 			.out_count		= 1, | ||||||
|  | 			.in_count		= response_size, | ||||||
|  | 			.send_index		= 0 | ||||||
|  | 		}); | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool PS2Controller::append_command_queue(PS2Device* device, uint8_t command, uint8_t data, uint8_t response_size) | ||||||
|  | 	{ | ||||||
|  | 		// NOTE: command queue push/pop must be done without interrupts
 | ||||||
|  | 		CriticalScope _; | ||||||
|  | 		ASSERT(device && (device == m_devices[0].ptr() || device == m_devices[1].ptr())); | ||||||
|  | 		if (m_command_queue.size() + 1 >= m_command_queue.capacity()) | ||||||
|  | 		{ | ||||||
|  | 			dprintln("PS/2 command queue full"); | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		m_command_queue.push(Command { | ||||||
|  | 			.state			= Command::State::NotSent, | ||||||
|  | 			.device_index	= (device == m_devices[0].ptr()) ? uint8_t(0) : uint8_t(1), | ||||||
|  | 			.out_data		= { command, data }, | ||||||
|  | 			.out_count		= 2, | ||||||
|  | 			.in_count		= response_size, | ||||||
|  | 			.send_index		= 0 | ||||||
|  | 		}); | ||||||
|  | 		return true; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void PS2Controller::update_command_queue() | ||||||
|  | 	{ | ||||||
|  | 		ASSERT(interrupts_enabled()); | ||||||
|  | 
 | ||||||
|  | 		if (m_command_queue.empty()) | ||||||
|  | 			return; | ||||||
|  | 		auto& command = m_command_queue.front(); | ||||||
|  | 		if (command.state == Command::State::WaitingResponse || command.state == Command::State::WaitingAck) | ||||||
|  | 			return; | ||||||
|  | 		ASSERT(command.send_index < command.out_count); | ||||||
|  | 		command.state = Command::State::WaitingAck; | ||||||
|  | 		if (auto ret = device_send_byte(command.device_index, command.out_data[command.send_index]); ret.is_error()) | ||||||
|  | 		{ | ||||||
|  | 			command.state = Command::State::Sending; | ||||||
|  | 			dwarnln_if(DEBUG_PS2, "PS/2 send command byte: {}", ret.error()); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bool PS2Controller::handle_command_byte(PS2Device* device, uint8_t byte) | ||||||
|  | 	{ | ||||||
|  | 		// NOTE: command queue push/pop must be done without interrupts
 | ||||||
|  | 		ASSERT(!interrupts_enabled()); | ||||||
|  | 
 | ||||||
|  | 		if (m_command_queue.empty()) | ||||||
|  | 			return false; | ||||||
|  | 		auto& command = m_command_queue.front(); | ||||||
|  | 
 | ||||||
|  | 		ASSERT(device && (device == m_devices[0].ptr() || device == m_devices[1].ptr())); | ||||||
|  | 		if (command.device_index != (device == m_devices[0].ptr()) ? 0 : 1) | ||||||
|  | 			return false; | ||||||
|  | 
 | ||||||
|  | 		switch (command.state) | ||||||
|  | 		{ | ||||||
|  | 			case Command::State::NotSent: | ||||||
|  | 			{ | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 			case Command::State::Sending: | ||||||
|  | 			{ | ||||||
|  | 				dwarnln_if(DEBUG_PS2, "PS/2 device sent byte while middle of command send"); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 			case Command::State::WaitingResponse: | ||||||
|  | 			{ | ||||||
|  | 				if (--command.in_count <= 0) | ||||||
|  | 					m_command_queue.pop(); | ||||||
|  | 				return false; | ||||||
|  | 			} | ||||||
|  | 			case Command::State::WaitingAck: | ||||||
|  | 			{ | ||||||
|  | 				switch (byte) | ||||||
|  | 				{ | ||||||
|  | 					case PS2::Response::ACK: | ||||||
|  | 					{ | ||||||
|  | 						if (++command.send_index < command.out_count) | ||||||
|  | 							command.state = Command::State::Sending; | ||||||
|  | 						else if (command.in_count > 0) | ||||||
|  | 							command.state = Command::State::WaitingResponse; | ||||||
|  | 						else | ||||||
|  | 							m_command_queue.pop(); | ||||||
|  | 						return true; | ||||||
|  | 					} | ||||||
|  | 					case PS2::Response::RESEND: | ||||||
|  | 						command.state = Command::State::Sending; | ||||||
|  | 						return true; | ||||||
|  | 					default: | ||||||
|  | 						dwarnln_if(DEBUG_PS2, "PS/2 expected ACK got {2H}", byte); | ||||||
|  | 						command.state = Command::State::Sending; | ||||||
|  | 						return true; | ||||||
|  | 				} | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		ASSERT_NOT_REACHED(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	BAN::ErrorOr<void> PS2Controller::initialize() | 	BAN::ErrorOr<void> PS2Controller::initialize() | ||||||
| 	{ | 	{ | ||||||
| 		ASSERT(s_instance == nullptr); | 		ASSERT(s_instance == nullptr); | ||||||
|  | @ -134,21 +227,25 @@ namespace Kernel::Input | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<void> PS2Controller::initialize_impl() | 	BAN::ErrorOr<void> PS2Controller::initialize_impl() | ||||||
| 	{ | 	{ | ||||||
| 		// Step 1: Initialise USB Controllers
 | 		// FIXME: Initialise USB Controllers
 | ||||||
| 		// FIXME
 |  | ||||||
| 
 | 
 | ||||||
| 		// Step 2: Determine if the PS/2 Controller Exists
 | 		// Determine if the PS/2 Controller Exists
 | ||||||
| 		// FIXME
 | 		auto* fadt = static_cast<const ACPI::FADT*>(ACPI::get().get_header("FACP"sv, 0)); | ||||||
|  | 		if (fadt && fadt->revision > 1 && !(fadt->iapc_boot_arch & (1 << 1))) | ||||||
|  | 		{ | ||||||
|  | 			dwarnln_if(DEBUG_PS2, "No PS/2 available"); | ||||||
|  | 			return {}; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		// Step 3: Disable Devices
 | 		// Disable Devices
 | ||||||
| 		TRY(send_command(PS2::Command::DISABLE_FIRST_PORT)); | 		TRY(send_command(PS2::Command::DISABLE_FIRST_PORT)); | ||||||
| 		TRY(send_command(PS2::Command::DISABLE_SECOND_PORT)); | 		TRY(send_command(PS2::Command::DISABLE_SECOND_PORT)); | ||||||
| 
 | 
 | ||||||
| 		// Step 4: Flush The Output Buffer
 | 		// Flush The Output Buffer
 | ||||||
| 		while (!read_byte().is_error()) | 		while (!read_byte().is_error()) | ||||||
| 			continue; | 			continue; | ||||||
| 		 | 		 | ||||||
| 		// Step 5: Set the Controller Configuration Byte
 | 		// Set the Controller Configuration Byte
 | ||||||
| 		TRY(send_command(PS2::Command::READ_CONFIG)); | 		TRY(send_command(PS2::Command::READ_CONFIG)); | ||||||
| 		uint8_t config = TRY(read_byte()); | 		uint8_t config = TRY(read_byte()); | ||||||
| 		config &= ~PS2::Config::INTERRUPT_FIRST_PORT; | 		config &= ~PS2::Config::INTERRUPT_FIRST_PORT; | ||||||
|  | @ -156,7 +253,7 @@ namespace Kernel::Input | ||||||
| 		config &= ~PS2::Config::TRANSLATION_FIRST_PORT; | 		config &= ~PS2::Config::TRANSLATION_FIRST_PORT; | ||||||
| 		TRY(send_command(PS2::Command::WRITE_CONFIG, config)); | 		TRY(send_command(PS2::Command::WRITE_CONFIG, config)); | ||||||
| 
 | 
 | ||||||
| 		// Step 6: Perform Controller Self Test
 | 		// Perform Controller Self Test
 | ||||||
| 		TRY(send_command(PS2::Command::TEST_CONTROLLER)); | 		TRY(send_command(PS2::Command::TEST_CONTROLLER)); | ||||||
| 		if (TRY(read_byte()) != PS2::Response::TEST_CONTROLLER_PASS) | 		if (TRY(read_byte()) != PS2::Response::TEST_CONTROLLER_PASS) | ||||||
| 		{ | 		{ | ||||||
|  | @ -166,7 +263,7 @@ namespace Kernel::Input | ||||||
| 		// NOTE: self test might reset the device so we set the config byte again
 | 		// NOTE: self test might reset the device so we set the config byte again
 | ||||||
| 		TRY(send_command(PS2::Command::WRITE_CONFIG, config)); | 		TRY(send_command(PS2::Command::WRITE_CONFIG, config)); | ||||||
| 
 | 
 | ||||||
| 		// Step 7: Determine If There Are 2 Channels
 | 		// Determine If There Are 2 Channels
 | ||||||
| 		bool valid_ports[2] { true, false }; | 		bool valid_ports[2] { true, false }; | ||||||
| 		if (config & PS2::Config::CLOCK_SECOND_PORT) | 		if (config & PS2::Config::CLOCK_SECOND_PORT) | ||||||
| 		{ | 		{ | ||||||
|  | @ -179,7 +276,7 @@ namespace Kernel::Input | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Step 8: Perform Interface Tests
 | 		// Perform Interface Tests
 | ||||||
| 		TRY(send_command(PS2::Command::TEST_FIRST_PORT)); | 		TRY(send_command(PS2::Command::TEST_FIRST_PORT)); | ||||||
| 		if (TRY(read_byte()) != PS2::Response::TEST_FIRST_PORT_PASS) | 		if (TRY(read_byte()) != PS2::Response::TEST_FIRST_PORT_PASS) | ||||||
| 		{ | 		{ | ||||||
|  | @ -197,49 +294,29 @@ namespace Kernel::Input | ||||||
| 		} | 		} | ||||||
| 		if (!valid_ports[0] && !valid_ports[1]) | 		if (!valid_ports[0] && !valid_ports[1]) | ||||||
| 			return {}; | 			return {}; | ||||||
| 		 |  | ||||||
| 		// Step 9: Enable Devices (and disable scanning)
 |  | ||||||
| 		for (uint8_t device = 0; device < 2; device++) |  | ||||||
| 		{ |  | ||||||
| 			if (!valid_ports[device]) |  | ||||||
| 				continue; |  | ||||||
| 			TRY(send_command(device == 0 ? PS2::Command::ENABLE_FIRST_PORT : PS2::Command::ENABLE_SECOND_PORT)); |  | ||||||
| 			if (set_scanning(device, false).is_error()) |  | ||||||
| 			{ |  | ||||||
| 				dwarnln_if(DEBUG_PS2, "PS/2 could not disable device scanning"); |  | ||||||
| 				valid_ports[device] = false; |  | ||||||
| 			} |  | ||||||
| 			TRY(send_command(device == 0 ? PS2::Command::DISABLE_FIRST_PORT : PS2::Command::DISABLE_SECOND_PORT)); |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		// Step 10: Reset Devices
 | 		// Initialize devices
 | ||||||
| 		for (uint8_t device = 0; device < 2; device++) | 		for (uint8_t device = 0; device < 2; device++) | ||||||
| 		{ | 		{ | ||||||
| 			if (!valid_ports[device]) | 			if (!valid_ports[device]) | ||||||
| 				continue; | 				continue; | ||||||
| 			if (auto ret = reset_device(device); ret.is_error()) | 			if (auto ret = send_command(device == 0 ? PS2::Command::ENABLE_FIRST_PORT : PS2::Command::ENABLE_SECOND_PORT); ret.is_error()) | ||||||
| 			{ | 			{ | ||||||
| 				dwarnln_if(DEBUG_PS2, "PS/2 device reset failed: {}", ret.error()); | 				dwarnln_if(DEBUG_PS2, "PS/2 device enable failed: {}", ret.error()); | ||||||
| 				valid_ports[device] = false; |  | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			if (auto ret = set_scanning(device, false); ret.is_error()) |  | ||||||
| 			{ |  | ||||||
| 				dwarnln_if(DEBUG_PS2, "PS/2 device scan disabling failed: {}", ret.error()); |  | ||||||
| 				valid_ports[device] = false; |  | ||||||
| 				continue; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// Step 11: Initialize Device Drivers
 |  | ||||||
| 		for (uint8_t device = 0; device < 2; device++) |  | ||||||
| 		{ |  | ||||||
| 			if (!valid_ports[device]) |  | ||||||
| 				continue; |  | ||||||
| 			if (auto res = initialize_device(device); res.is_error()) | 			if (auto res = initialize_device(device); res.is_error()) | ||||||
|  | 			{ | ||||||
| 				dwarnln_if(DEBUG_PS2, "PS/2 device initialization failed: {}", res.error()); | 				dwarnln_if(DEBUG_PS2, "PS/2 device initialization failed: {}", res.error()); | ||||||
|  | 				(void)send_command(device == 0 ? PS2::Command::DISABLE_FIRST_PORT : PS2::Command::DISABLE_SECOND_PORT); | ||||||
|  | 				continue; | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		if (!m_devices[0] && !m_devices[1]) | ||||||
|  | 			return {}; | ||||||
|  | 
 | ||||||
|  | 		// Enable irqs on valid devices
 | ||||||
| 		if (m_devices[0]) | 		if (m_devices[0]) | ||||||
| 		{ | 		{ | ||||||
| 			m_devices[0]->set_irq(PS2::IRQ::DEVICE0); | 			m_devices[0]->set_irq(PS2::IRQ::DEVICE0); | ||||||
|  | @ -255,6 +332,7 @@ namespace Kernel::Input | ||||||
| 
 | 
 | ||||||
| 		TRY(send_command(PS2::Command::WRITE_CONFIG, config)); | 		TRY(send_command(PS2::Command::WRITE_CONFIG, config)); | ||||||
| 
 | 
 | ||||||
|  | 		// Send device initialization sequence after interrupts are enabled
 | ||||||
| 		for (uint8_t device = 0; device < 2; device++) | 		for (uint8_t device = 0; device < 2; device++) | ||||||
| 		{ | 		{ | ||||||
| 			if (!m_devices[device]) | 			if (!m_devices[device]) | ||||||
|  | @ -268,9 +346,25 @@ namespace Kernel::Input | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<void> PS2Controller::initialize_device(uint8_t device) | 	BAN::ErrorOr<void> PS2Controller::initialize_device(uint8_t device) | ||||||
| 	{ | 	{ | ||||||
| 		TRY(device_send_byte(device, PS2::DeviceCommand::IDENTIFY)); | 		// Reset device
 | ||||||
| 		TRY(device_read_ack(device)); | 		TRY(device_send_byte_and_wait_ack(device, PS2::DeviceCommand::RESET)); | ||||||
|  | 		if (TRY(read_byte()) != PS2::Response::SELF_TEST_PASS) | ||||||
|  | 		{ | ||||||
|  | 			dwarnln_if(DEBUG_PS2, "PS/2 device self test failed"); | ||||||
|  | 			return BAN::Error::from_errno(ENODEV); | ||||||
|  | 		} | ||||||
|  | 		while (!read_byte().is_error()) | ||||||
|  | 			continue; | ||||||
| 
 | 
 | ||||||
|  | 		// Disable scanning and flush buffer
 | ||||||
|  | 		TRY(device_send_byte_and_wait_ack(device, PS2::DeviceCommand::DISABLE_SCANNING)); | ||||||
|  | 		while (!read_byte().is_error()) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		// Identify device
 | ||||||
|  | 		TRY(device_send_byte_and_wait_ack(device, PS2::DeviceCommand::IDENTIFY)); | ||||||
|  | 
 | ||||||
|  | 		// Read up to 2 identification bytes
 | ||||||
| 		uint8_t bytes[2] {}; | 		uint8_t bytes[2] {}; | ||||||
| 		uint8_t index = 0; | 		uint8_t index = 0; | ||||||
| 		for (uint8_t i = 0; i < 2; i++) | 		for (uint8_t i = 0; i < 2; i++) | ||||||
|  | @ -286,41 +380,19 @@ namespace Kernel::Input | ||||||
| 		{ | 		{ | ||||||
| 			dprintln_if(DEBUG_PS2, "PS/2 found mouse"); | 			dprintln_if(DEBUG_PS2, "PS/2 found mouse"); | ||||||
| 			m_devices[device] = TRY(PS2Mouse::create(*this)); | 			m_devices[device] = TRY(PS2Mouse::create(*this)); | ||||||
|  | 			return {}; | ||||||
| 		} | 		} | ||||||
|  | 
 | ||||||
| 		// MF2 Keyboard
 | 		// MF2 Keyboard
 | ||||||
| 		else if (index == 2 && (bytes[0] == 0xAB && bytes[1] == 0x83)) | 		if (index == 2 && (bytes[0] == 0xAB && (bytes[1] == 0x83 || bytes[1] == 0x41))) | ||||||
| 		{ | 		{ | ||||||
| 			dprintln_if(DEBUG_PS2, "PS/2 found keyboard"); | 			dprintln_if(DEBUG_PS2, "PS/2 found keyboard"); | ||||||
| 			m_devices[device] = TRY(PS2Keyboard::create(*this)); | 			m_devices[device] = TRY(PS2Keyboard::create(*this)); | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (m_devices[device]) |  | ||||||
| 			return {}; | 			return {}; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		dprintln_if(DEBUG_PS2, "PS/2 unsupported device {2H} {2H} ({} bytes) on port {}", bytes[0], bytes[1], index, device); | 		dprintln_if(DEBUG_PS2, "PS/2 unsupported device {2H} {2H} ({} bytes) on port {}", bytes[0], bytes[1], index, device); | ||||||
| 		return BAN::Error::from_errno(ENOTSUP); | 		return BAN::Error::from_errno(ENOTSUP); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<void> PS2Controller::reset_device(uint8_t device) |  | ||||||
| 	{ |  | ||||||
| 		TRY(device_send_byte(device, PS2::DeviceCommand::RESET)); |  | ||||||
| 		TRY(device_read_ack(device)); |  | ||||||
| 		if (TRY(read_byte()) != PS2::Response::SELF_TEST_PASS) |  | ||||||
| 		{ |  | ||||||
| 			dwarnln_if(DEBUG_PS2, "PS/2 device self test failed"); |  | ||||||
| 			return BAN::Error::from_errno(ENODEV); |  | ||||||
| 		} |  | ||||||
| 		// device might send extra data
 |  | ||||||
| 		while (!read_byte().is_error()) |  | ||||||
| 			continue; |  | ||||||
| 		return {}; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	BAN::ErrorOr<void> PS2Controller::set_scanning(uint8_t device, bool enabled) |  | ||||||
| 	{ |  | ||||||
| 		TRY(device_send_byte(device, enabled ? PS2::DeviceCommand::ENABLE_SCANNING : PS2::DeviceCommand::DISABLE_SCANNING)); |  | ||||||
| 		TRY(device_read_ack(device)); |  | ||||||
| 		return {}; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -17,114 +17,19 @@ namespace Kernel::Input | ||||||
| 
 | 
 | ||||||
| 	bool PS2Device::append_command_queue(uint8_t command, uint8_t response_size) | 	bool PS2Device::append_command_queue(uint8_t command, uint8_t response_size) | ||||||
| 	{ | 	{ | ||||||
| 		CriticalScope _; | 		return m_controller.append_command_queue(this, command, response_size); | ||||||
| 		if (m_command_queue.size() + 1 >= m_command_queue.capacity()) |  | ||||||
| 		{ |  | ||||||
| 			dprintln("PS/2 command queue full"); |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 		m_command_queue.push(Command { |  | ||||||
| 			.out_data	= { command, 0x00 }, |  | ||||||
| 			.out_count	= 1, |  | ||||||
| 			.in_count	= response_size, |  | ||||||
| 			.send_index	= 0 |  | ||||||
| 		}); |  | ||||||
| 		update_command(); |  | ||||||
| 		return true; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	bool PS2Device::append_command_queue(uint8_t command, uint8_t data, uint8_t response_size) | 	bool PS2Device::append_command_queue(uint8_t command, uint8_t data, uint8_t response_size) | ||||||
| 	{ | 	{ | ||||||
| 		CriticalScope _; | 		return m_controller.append_command_queue(this, command, data, response_size); | ||||||
| 		if (m_command_queue.size() + 1 >= m_command_queue.capacity()) |  | ||||||
| 		{ |  | ||||||
| 			dprintln("PS/2 command queue full"); |  | ||||||
| 			return false; |  | ||||||
| 		} |  | ||||||
| 		m_command_queue.push(Command { |  | ||||||
| 			.out_data	= { command, data }, |  | ||||||
| 			.out_count	= 2, |  | ||||||
| 			.in_count	= response_size, |  | ||||||
| 			.send_index	= 0 |  | ||||||
| 		}); |  | ||||||
| 		update_command(); |  | ||||||
| 		return true; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void PS2Device::handle_irq() | 	void PS2Device::handle_irq() | ||||||
| 	{ | 	{ | ||||||
| 		uint8_t byte = IO::inb(PS2::IOPort::DATA); | 		uint8_t byte = IO::inb(PS2::IOPort::DATA); | ||||||
| 
 | 		if (!m_controller.handle_command_byte(this, byte)) | ||||||
| 		switch (m_state) | 			handle_byte(byte); | ||||||
| 		{ |  | ||||||
| 			case State::WaitingAck: |  | ||||||
| 			{ |  | ||||||
| 				switch (byte) |  | ||||||
| 				{ |  | ||||||
| 					case PS2::Response::ACK: |  | ||||||
| 					{ |  | ||||||
| 						auto& command = m_command_queue.front(); |  | ||||||
| 						if (++command.send_index < command.out_count) |  | ||||||
| 							m_state = State::Normal; |  | ||||||
| 						else if (command.in_count > 0) |  | ||||||
| 							m_state = State::WaitingResponse; |  | ||||||
| 						else |  | ||||||
| 						{ |  | ||||||
| 							m_command_queue.pop(); |  | ||||||
| 							m_state = State::Normal; |  | ||||||
| 							m_controller.unlock_command(this); |  | ||||||
| 						} |  | ||||||
| 						break; |  | ||||||
| 					} |  | ||||||
| 					case PS2::Response::RESEND: |  | ||||||
| 						m_state = State::Normal; |  | ||||||
| 						break; |  | ||||||
| 					default: |  | ||||||
| 						handle_device_command_response(byte); |  | ||||||
| 						break; |  | ||||||
| 				} |  | ||||||
| 				break; |  | ||||||
| 			} |  | ||||||
| 			case State::WaitingResponse: |  | ||||||
| 			{ |  | ||||||
| 				if (--m_command_queue.front().in_count <= 0) |  | ||||||
| 				{ |  | ||||||
| 					m_command_queue.pop(); |  | ||||||
| 					m_state = State::Normal; |  | ||||||
| 					m_controller.unlock_command(this); |  | ||||||
| 				} |  | ||||||
| 				handle_byte(byte); |  | ||||||
| 				break; |  | ||||||
| 			} |  | ||||||
| 			case State::Normal: |  | ||||||
| 			{ |  | ||||||
| 				handle_byte(byte); |  | ||||||
| 				break; |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		update_command(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	void PS2Device::update_command() |  | ||||||
| 	{ |  | ||||||
| 		ASSERT(!interrupts_enabled()); |  | ||||||
| 
 |  | ||||||
| 		if (m_state != State::Normal) |  | ||||||
| 			return; |  | ||||||
| 		if (m_command_queue.empty()) |  | ||||||
| 			return; |  | ||||||
| 
 |  | ||||||
| 		const auto& command = m_command_queue.front(); |  | ||||||
| 		ASSERT(command.send_index < command.out_count); |  | ||||||
| 
 |  | ||||||
| 		if (!m_controller.lock_command(this)) |  | ||||||
| 			return; |  | ||||||
| 
 |  | ||||||
| 		m_state = State::WaitingAck; |  | ||||||
| 		auto ret = m_controller.device_send_byte(this, command.out_data[command.send_index]); |  | ||||||
| 		if (ret.is_error()) |  | ||||||
| 			dwarnln("Could not send byte to device: {}", ret.error()); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -30,22 +30,14 @@ namespace Kernel::Input | ||||||
| 		append_command_queue(PS2::DeviceCommand::ENABLE_SCANNING, 0); | 		append_command_queue(PS2::DeviceCommand::ENABLE_SCANNING, 0); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void PS2Keyboard::handle_device_command_response(uint8_t byte) |  | ||||||
| 	{ |  | ||||||
| 		switch (byte) |  | ||||||
| 		{ |  | ||||||
| 			case PS2::KBResponse::KEY_ERROR_OR_BUFFER_OVERRUN1: |  | ||||||
| 			case PS2::KBResponse::KEY_ERROR_OR_BUFFER_OVERRUN2: |  | ||||||
| 				dwarnln("Key detection error or internal buffer overrun"); |  | ||||||
| 				break; |  | ||||||
| 			default: |  | ||||||
| 				dwarnln("Unhandeled byte {2H}", byte); |  | ||||||
| 				break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	void PS2Keyboard::handle_byte(uint8_t byte) | 	void PS2Keyboard::handle_byte(uint8_t byte) | ||||||
| 	{ | 	{ | ||||||
|  | 		if (byte == PS2::KBResponse::KEY_ERROR_OR_BUFFER_OVERRUN1 || byte == PS2::KBResponse::KEY_ERROR_OR_BUFFER_OVERRUN2) | ||||||
|  | 		{ | ||||||
|  | 			dwarnln("Key detection error or internal buffer overrun"); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		m_byte_buffer[m_byte_index++] = byte; | 		m_byte_buffer[m_byte_index++] = byte; | ||||||
| 		if (byte == 0xE0 || byte == 0xF0) | 		if (byte == 0xE0 || byte == 0xF0) | ||||||
| 			return; | 			return; | ||||||
|  |  | ||||||
|  | @ -70,16 +70,6 @@ namespace Kernel::Input | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	void PS2Mouse::handle_device_command_response(uint8_t byte) |  | ||||||
| 	{ |  | ||||||
| 		switch (byte) |  | ||||||
| 		{ |  | ||||||
| 			default: |  | ||||||
| 				dwarnln("Unhandeled byte {2H}", byte); |  | ||||||
| 				break; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	void PS2Mouse::handle_byte(uint8_t byte) | 	void PS2Mouse::handle_byte(uint8_t byte) | ||||||
| 	{ | 	{ | ||||||
| 		if (!m_enabled) | 		if (!m_enabled) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue