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: | ||||
| 		PS2Controller() = default; | ||||
| 		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<void> send_byte(uint16_t port, uint8_t byte); | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ namespace Kernel::Input | |||
| 
 | ||||
| 	protected: | ||||
| 		PS2Device(PS2Controller&, InputDevice::Type type); | ||||
| 		virtual ~PS2Device(); | ||||
| 
 | ||||
| 	protected: | ||||
| 		PS2Controller& m_controller; | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ | |||
| 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; | ||||
| 
 | ||||
|  | @ -238,6 +238,15 @@ namespace Kernel::Input | |||
| 		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) | ||||
| 	{ | ||||
| 		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]) | ||||
| 			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
 | ||||
| 		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()); | ||||
| 				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()); | ||||
| 				(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]) | ||||
| 			return {}; | ||||
| 			return; | ||||
| 
 | ||||
| 		// Enable irqs on valid devices
 | ||||
| 		if (m_devices[0]) | ||||
|  | @ -362,21 +407,21 @@ namespace Kernel::Input | |||
| 			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
 | ||||
| 		for (uint8_t i = 0; i < 2; i++) | ||||
| 		{ | ||||
| 			if (!m_devices[i]) | ||||
| 				continue; | ||||
| 			m_devices[i]->send_initialize(); | ||||
| 			DevFileSystem::get().add_device(m_devices[i]); | ||||
| 		} | ||||
| 
 | ||||
| 		return {}; | ||||
| 			if (m_devices[i]) | ||||
| 				m_devices[i]->send_initialize(); | ||||
| 	} | ||||
| 
 | ||||
| 	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
 | ||||
| 		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) | ||||
| 		: InputDevice(type) | ||||
| 		, 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) | ||||
| 	{ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue