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 | ||||
| 
 | ||||
| #include <BAN/CircularQueue.h> | ||||
| #include <BAN/UniqPtr.h> | ||||
| #include <kernel/Device/Device.h> | ||||
| #include <kernel/Input/PS2/Config.h> | ||||
|  | @ -17,19 +18,17 @@ namespace Kernel::Input | |||
| 		static BAN::ErrorOr<void> initialize(); | ||||
| 		static PS2Controller& get(); | ||||
| 
 | ||||
| 		BAN::ErrorOr<void> device_send_byte(PS2Device* device, uint8_t byte); | ||||
| 
 | ||||
| 		[[nodiscard]] bool lock_command(PS2Device*); | ||||
| 		void unlock_command(PS2Device*); | ||||
| 		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<void> initialize_impl(); | ||||
| 		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<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> 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: | ||||
| 		BAN::RefPtr<PS2Device> m_devices[2]; | ||||
| 		RecursiveSpinLock m_lock; | ||||
| 
 | ||||
| 		PS2Device* m_executing_device	{ nullptr }; | ||||
| 		PS2Device* m_pending_device		{ nullptr }; | ||||
| 		BAN::CircularQueue<Command, 128> m_command_queue; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -1,6 +1,5 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/CircularQueue.h> | ||||
| #include <kernel/Input/PS2/Controller.h> | ||||
| #include <kernel/InterruptController.h> | ||||
| 
 | ||||
|  | @ -20,39 +19,16 @@ namespace Kernel::Input | |||
| 		virtual void handle_irq() final override; | ||||
| 
 | ||||
| 		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 dev_t rdev() const final override { return m_rdev; } | ||||
| 
 | ||||
| 	private: | ||||
| 		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; | ||||
| 		}; | ||||
| 		virtual void update() final override { m_controller.update_command_queue(); } | ||||
| 
 | ||||
| 	private: | ||||
| 		const BAN::String m_name; | ||||
| 		const dev_t m_rdev; | ||||
| 
 | ||||
| 		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 handle_byte(uint8_t) final override; | ||||
| 		virtual void handle_device_command_response(uint8_t) final override; | ||||
| 
 | ||||
| 	private: | ||||
| 		PS2Keyboard(PS2Controller& controller); | ||||
|  |  | |||
|  | @ -20,7 +20,6 @@ namespace Kernel::Input | |||
| 		virtual void send_initialize() override; | ||||
| 
 | ||||
| 		virtual void handle_byte(uint8_t) final override; | ||||
| 		virtual void handle_device_command_response(uint8_t) final override; | ||||
| 
 | ||||
| 	private: | ||||
| 		PS2Mouse(PS2Controller& controller); | ||||
|  |  | |||
|  | @ -21,6 +21,7 @@ namespace Kernel::Input | |||
| 
 | ||||
| 	BAN::ErrorOr<void> PS2Controller::send_byte(uint16_t port, uint8_t byte) | ||||
| 	{ | ||||
| 		ASSERT(interrupts_enabled()); | ||||
| 		LockGuard _(m_lock); | ||||
| 		uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ps2_timeout_ms; | ||||
| 		while (SystemTimer::get().ms_since_boot() < timeout) | ||||
|  | @ -35,6 +36,7 @@ namespace Kernel::Input | |||
| 
 | ||||
| 	BAN::ErrorOr<uint8_t> PS2Controller::read_byte() | ||||
| 	{ | ||||
| 		ASSERT(interrupts_enabled()); | ||||
| 		LockGuard _(m_lock); | ||||
| 		uint64_t timeout = SystemTimer::get().ms_since_boot() + s_ps2_timeout_ms; | ||||
| 		while (SystemTimer::get().ms_since_boot() < timeout) | ||||
|  | @ -61,31 +63,6 @@ namespace Kernel::Input | |||
| 		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) | ||||
| 	{ | ||||
| 		LockGuard _(m_lock); | ||||
|  | @ -95,25 +72,141 @@ namespace Kernel::Input | |||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> PS2Controller::device_send_byte(PS2Device* device, 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) | ||||
| 	BAN::ErrorOr<void> PS2Controller::device_send_byte_and_wait_ack(uint8_t device_index, uint8_t byte) | ||||
| 	{ | ||||
| 		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 {}; | ||||
| 	} | ||||
| 
 | ||||
| 	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() | ||||
| 	{ | ||||
| 		ASSERT(s_instance == nullptr); | ||||
|  | @ -134,21 +227,25 @@ namespace Kernel::Input | |||
| 
 | ||||
| 	BAN::ErrorOr<void> PS2Controller::initialize_impl() | ||||
| 	{ | ||||
| 		// Step 1: Initialise USB Controllers
 | ||||
| 		// FIXME
 | ||||
| 		// FIXME: Initialise USB Controllers
 | ||||
| 
 | ||||
| 		// Step 2: Determine if the PS/2 Controller Exists
 | ||||
| 		// FIXME
 | ||||
| 		// Determine if the PS/2 Controller Exists
 | ||||
| 		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_SECOND_PORT)); | ||||
| 
 | ||||
| 		// Step 4: Flush The Output Buffer
 | ||||
| 		// Flush The Output Buffer
 | ||||
| 		while (!read_byte().is_error()) | ||||
| 			continue; | ||||
| 		 | ||||
| 		// Step 5: Set the Controller Configuration Byte
 | ||||
| 		// Set the Controller Configuration Byte
 | ||||
| 		TRY(send_command(PS2::Command::READ_CONFIG)); | ||||
| 		uint8_t config = TRY(read_byte()); | ||||
| 		config &= ~PS2::Config::INTERRUPT_FIRST_PORT; | ||||
|  | @ -156,7 +253,7 @@ namespace Kernel::Input | |||
| 		config &= ~PS2::Config::TRANSLATION_FIRST_PORT; | ||||
| 		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)); | ||||
| 		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
 | ||||
| 		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 }; | ||||
| 		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)); | ||||
| 		if (TRY(read_byte()) != PS2::Response::TEST_FIRST_PORT_PASS) | ||||
| 		{ | ||||
|  | @ -198,48 +295,28 @@ namespace Kernel::Input | |||
| 		if (!valid_ports[0] && !valid_ports[1]) | ||||
| 			return {}; | ||||
| 
 | ||||
| 		// Step 9: Enable Devices (and disable scanning)
 | ||||
| 		// Initialize devices
 | ||||
| 		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()) | ||||
| 			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 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
 | ||||
| 		for (uint8_t device = 0; device < 2; device++) | ||||
| 		{ | ||||
| 			if (!valid_ports[device]) | ||||
| 				continue; | ||||
| 			if (auto ret = reset_device(device); ret.is_error()) | ||||
| 			{ | ||||
| 				dwarnln_if(DEBUG_PS2, "PS/2 device reset failed: {}", ret.error()); | ||||
| 				valid_ports[device] = false; | ||||
| 				dwarnln_if(DEBUG_PS2, "PS/2 device enable failed: {}", ret.error()); | ||||
| 				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()) | ||||
| 			{ | ||||
| 				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]) | ||||
| 		{ | ||||
| 			m_devices[0]->set_irq(PS2::IRQ::DEVICE0); | ||||
|  | @ -255,6 +332,7 @@ namespace Kernel::Input | |||
| 
 | ||||
| 		TRY(send_command(PS2::Command::WRITE_CONFIG, config)); | ||||
| 
 | ||||
| 		// Send device initialization sequence after interrupts are enabled
 | ||||
| 		for (uint8_t device = 0; device < 2; device++) | ||||
| 		{ | ||||
| 			if (!m_devices[device]) | ||||
|  | @ -268,9 +346,25 @@ namespace Kernel::Input | |||
| 
 | ||||
| 	BAN::ErrorOr<void> PS2Controller::initialize_device(uint8_t device) | ||||
| 	{ | ||||
| 		TRY(device_send_byte(device, PS2::DeviceCommand::IDENTIFY)); | ||||
| 		TRY(device_read_ack(device)); | ||||
| 		// Reset 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 index = 0; | ||||
| 		for (uint8_t i = 0; i < 2; i++) | ||||
|  | @ -286,41 +380,19 @@ namespace Kernel::Input | |||
| 		{ | ||||
| 			dprintln_if(DEBUG_PS2, "PS/2 found mouse"); | ||||
| 			m_devices[device] = TRY(PS2Mouse::create(*this)); | ||||
| 			return {}; | ||||
| 		} | ||||
| 
 | ||||
| 		// 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"); | ||||
| 			m_devices[device] = TRY(PS2Keyboard::create(*this)); | ||||
| 		} | ||||
| 
 | ||||
| 		if (m_devices[device]) | ||||
| 			return {}; | ||||
| 		} | ||||
| 
 | ||||
| 		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); | ||||
| 	} | ||||
| 
 | ||||
| 	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) | ||||
| 	{ | ||||
| 		CriticalScope _; | ||||
| 		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; | ||||
| 		return m_controller.append_command_queue(this, command, response_size); | ||||
| 	} | ||||
| 
 | ||||
| 	bool PS2Device::append_command_queue(uint8_t command, uint8_t data, uint8_t response_size) | ||||
| 	{ | ||||
| 		CriticalScope _; | ||||
| 		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; | ||||
| 		return m_controller.append_command_queue(this, command, data, response_size); | ||||
| 	} | ||||
| 
 | ||||
| 	void PS2Device::handle_irq() | ||||
| 	{ | ||||
| 		uint8_t byte = IO::inb(PS2::IOPort::DATA); | ||||
| 
 | ||||
| 		switch (m_state) | ||||
| 		{ | ||||
| 			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); | ||||
| 				} | ||||
| 		if (!m_controller.handle_command_byte(this, byte)) | ||||
| 			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); | ||||
| 	} | ||||
| 
 | ||||
| 	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) | ||||
| 	{ | ||||
| 		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; | ||||
| 		if (byte == 0xE0 || byte == 0xF0) | ||||
| 			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) | ||||
| 	{ | ||||
| 		if (!m_enabled) | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue