forked from Bananymous/banan-os
				
			Kernel: Increase PS2 timeout to 300 ms, load PS2 in separate thread
PS/2 seems to hit command timeout sometimes on slow emulation so increase the timeouts. Also move PS/2 device initialization to a different thread because device indentification waits for timeouts.
This commit is contained in:
		
							parent
							
								
									92e4078287
								
							
						
					
					
						commit
						892e16dfb1
					
				|  | @ -27,7 +27,9 @@ namespace Kernel::Input | ||||||
| 	private: | 	private: | ||||||
| 		PS2Controller() = default; | 		PS2Controller() = default; | ||||||
| 		BAN::ErrorOr<void> initialize_impl(uint8_t scancode_set); | 		BAN::ErrorOr<void> initialize_impl(uint8_t scancode_set); | ||||||
| 		BAN::ErrorOr<void> initialize_device(uint8_t, uint8_t scancode_set); | 		BAN::ErrorOr<void> identify_device(uint8_t, uint8_t scancode_set); | ||||||
|  | 
 | ||||||
|  | 		void device_initialize_task(void*); | ||||||
| 
 | 
 | ||||||
| 		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); | ||||||
|  |  | ||||||
|  | @ -22,6 +22,7 @@ namespace Kernel::Input | ||||||
| 
 | 
 | ||||||
| 	protected: | 	protected: | ||||||
| 		PS2Device(PS2Controller&, InputDevice::Type type); | 		PS2Device(PS2Controller&, InputDevice::Type type); | ||||||
|  | 		virtual ~PS2Device(); | ||||||
| 
 | 
 | ||||||
| 	protected: | 	protected: | ||||||
| 		PS2Controller& m_controller; | 		PS2Controller& m_controller; | ||||||
|  |  | ||||||
|  | @ -12,7 +12,7 @@ | ||||||
| namespace Kernel::Input | namespace Kernel::Input | ||||||
| { | { | ||||||
| 
 | 
 | ||||||
| 	static constexpr uint64_t s_ps2_timeout_ms = 100; | 	static constexpr uint64_t s_ps2_timeout_ms = 300; | ||||||
| 
 | 
 | ||||||
| 	static PS2Controller* s_instance = nullptr; | 	static PS2Controller* s_instance = nullptr; | ||||||
| 
 | 
 | ||||||
|  | @ -238,6 +238,15 @@ namespace Kernel::Input | ||||||
| 		return *s_instance; | 		return *s_instance; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	struct PS2DeviceInitInfo | ||||||
|  | 	{ | ||||||
|  | 		PS2Controller* controller; | ||||||
|  | 		bool valid_ports[2]; | ||||||
|  | 		uint8_t scancode_set; | ||||||
|  | 		uint8_t config; | ||||||
|  | 		BAN::Atomic<bool> thread_started; | ||||||
|  | 	}; | ||||||
|  | 
 | ||||||
| 	BAN::ErrorOr<void> PS2Controller::initialize_impl(uint8_t scancode_set) | 	BAN::ErrorOr<void> PS2Controller::initialize_impl(uint8_t scancode_set) | ||||||
| 	{ | 	{ | ||||||
| 		constexpr size_t iapc_flag_off = offsetof(ACPI::FADT, iapc_boot_arch); | 		constexpr size_t iapc_flag_off = offsetof(ACPI::FADT, iapc_boot_arch); | ||||||
|  | @ -315,6 +324,54 @@ namespace Kernel::Input | ||||||
| 		if (!valid_ports[0] && !valid_ports[1]) | 		if (!valid_ports[0] && !valid_ports[1]) | ||||||
| 			return {}; | 			return {}; | ||||||
| 
 | 
 | ||||||
|  | 		// Reserve IRQs
 | ||||||
|  | 		if (valid_ports[0] && InterruptController::get().reserve_irq(PS2::IRQ::DEVICE0).is_error()) | ||||||
|  | 		{ | ||||||
|  | 			dwarnln("Could not reserve irq for PS/2 port 1"); | ||||||
|  | 			valid_ports[0] = false; | ||||||
|  | 		} | ||||||
|  | 		if (valid_ports[1] && InterruptController::get().reserve_irq(PS2::IRQ::DEVICE1).is_error()) | ||||||
|  | 		{ | ||||||
|  | 			dwarnln("Could not reserve irq for PS/2 port 2"); | ||||||
|  | 			valid_ports[1] = false; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		PS2DeviceInitInfo info { | ||||||
|  | 			.controller = this, | ||||||
|  | 			.valid_ports = { valid_ports[0], valid_ports[1] }, | ||||||
|  | 			.scancode_set = scancode_set, | ||||||
|  | 			.config = config, | ||||||
|  | 			.thread_started { false }, | ||||||
|  | 		}; | ||||||
|  | 
 | ||||||
|  | 		auto* init_thread = TRY(Thread::create_kernel( | ||||||
|  | 			[](void* info) { | ||||||
|  | 				static_cast<PS2DeviceInitInfo*>(info)->controller->device_initialize_task(info); | ||||||
|  | 			}, &info, nullptr | ||||||
|  | 		)); | ||||||
|  | 		TRY(Processor::scheduler().add_thread(init_thread)); | ||||||
|  | 
 | ||||||
|  | 		while (!info.thread_started) | ||||||
|  | 			Processor::pause(); | ||||||
|  | 
 | ||||||
|  | 		return {}; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	void PS2Controller::device_initialize_task(void* _info) | ||||||
|  | 	{ | ||||||
|  | 		bool valid_ports[2]; | ||||||
|  | 		uint8_t scancode_set; | ||||||
|  | 		uint8_t config; | ||||||
|  | 
 | ||||||
|  | 		{ | ||||||
|  | 			auto& info = *static_cast<PS2DeviceInitInfo*>(_info); | ||||||
|  | 			valid_ports[0] = info.valid_ports[0]; | ||||||
|  | 			valid_ports[1] = info.valid_ports[1]; | ||||||
|  | 			scancode_set = info.scancode_set; | ||||||
|  | 			config = info.config; | ||||||
|  | 			info.thread_started = true; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
| 		// Initialize devices
 | 		// Initialize devices
 | ||||||
| 		for (uint8_t device = 0; device < 2; device++) | 		for (uint8_t device = 0; device < 2; device++) | ||||||
| 		{ | 		{ | ||||||
|  | @ -325,7 +382,7 @@ namespace Kernel::Input | ||||||
| 				dwarnln_if(DEBUG_PS2, "PS/2 device enable failed: {}", ret.error()); | 				dwarnln_if(DEBUG_PS2, "PS/2 device enable failed: {}", ret.error()); | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			if (auto res = initialize_device(device, scancode_set); res.is_error()) | 			if (auto res = identify_device(device, scancode_set); 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); | 				(void)send_command(device == 0 ? PS2::Command::DISABLE_FIRST_PORT : PS2::Command::DISABLE_SECOND_PORT); | ||||||
|  | @ -333,20 +390,8 @@ namespace Kernel::Input | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Reserve IRQs
 |  | ||||||
| 		if (m_devices[0] && InterruptController::get().reserve_irq(PS2::IRQ::DEVICE0).is_error()) |  | ||||||
| 		{ |  | ||||||
| 			dwarnln("Could not reserve irq for PS/2 port 1"); |  | ||||||
| 			m_devices[0].clear(); |  | ||||||
| 		} |  | ||||||
| 		if (m_devices[1] && InterruptController::get().reserve_irq(PS2::IRQ::DEVICE1).is_error()) |  | ||||||
| 		{ |  | ||||||
| 			dwarnln("Could not reserve irq for PS/2 port 2"); |  | ||||||
| 			m_devices[1].clear(); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (!m_devices[0] && !m_devices[1]) | 		if (!m_devices[0] && !m_devices[1]) | ||||||
| 			return {}; | 			return; | ||||||
| 
 | 
 | ||||||
| 		// Enable irqs on valid devices
 | 		// Enable irqs on valid devices
 | ||||||
| 		if (m_devices[0]) | 		if (m_devices[0]) | ||||||
|  | @ -362,21 +407,21 @@ namespace Kernel::Input | ||||||
| 			config |= PS2::Config::INTERRUPT_SECOND_PORT; | 			config |= PS2::Config::INTERRUPT_SECOND_PORT; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		TRY(send_command(PS2::Command::WRITE_CONFIG, config)); | 		if (auto ret = send_command(PS2::Command::WRITE_CONFIG, config); ret.is_error()) | ||||||
|  | 		{ | ||||||
|  | 			dwarnln("PS2 failed to enable interrupts: {}", ret.error()); | ||||||
|  | 			m_devices[0].clear(); | ||||||
|  | 			m_devices[1].clear(); | ||||||
|  | 			return; | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		// Send device initialization sequence after interrupts are enabled
 | 		// Send device initialization sequence after interrupts are enabled
 | ||||||
| 		for (uint8_t i = 0; i < 2; i++) | 		for (uint8_t i = 0; i < 2; i++) | ||||||
| 		{ | 			if (m_devices[i]) | ||||||
| 			if (!m_devices[i]) | 				m_devices[i]->send_initialize(); | ||||||
| 				continue; |  | ||||||
| 			m_devices[i]->send_initialize(); |  | ||||||
| 			DevFileSystem::get().add_device(m_devices[i]); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		return {}; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<void> PS2Controller::initialize_device(uint8_t device, uint8_t scancode_set) | 	BAN::ErrorOr<void> PS2Controller::identify_device(uint8_t device, uint8_t scancode_set) | ||||||
| 	{ | 	{ | ||||||
| 		// Reset device
 | 		// Reset device
 | ||||||
| 		TRY(device_send_byte_and_wait_ack(device, PS2::DeviceCommand::RESET)); | 		TRY(device_send_byte_and_wait_ack(device, PS2::DeviceCommand::RESET)); | ||||||
|  |  | ||||||
|  | @ -9,7 +9,14 @@ namespace Kernel::Input | ||||||
| 	PS2Device::PS2Device(PS2Controller& controller, InputDevice::Type type) | 	PS2Device::PS2Device(PS2Controller& controller, InputDevice::Type type) | ||||||
| 		: InputDevice(type) | 		: InputDevice(type) | ||||||
| 		, m_controller(controller) | 		, m_controller(controller) | ||||||
| 	{ } | 	{ | ||||||
|  | 		DevFileSystem::get().add_device(this); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	PS2Device::~PS2Device() | ||||||
|  | 	{ | ||||||
|  | 		DevFileSystem::get().remove_device(this); | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	bool PS2Device::append_command_queue(uint8_t command, uint8_t response_size) | 	bool PS2Device::append_command_queue(uint8_t command, uint8_t response_size) | ||||||
| 	{ | 	{ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue