Kernel: Rework the whole input system
We now use Device abstraction that will allow us to provide devices to userspace through /dev. Currently Shell reads from first and only device (it being PS/2 Keyboard).
This commit is contained in:
		
							parent
							
								
									e5c3486826
								
							
						
					
					
						commit
						fa8e921ee8
					
				|  | @ -41,11 +41,14 @@ kernel/APIC.o					\ | |||
| kernel/build_libc.o				\ | ||||
| kernel/CPUID.o					\ | ||||
| kernel/Debug.o					\ | ||||
| kernel/Device.o					\ | ||||
| kernel/Font.o					\ | ||||
| kernel/FS/Ext2.o				\ | ||||
| kernel/FS/Inode.o				\ | ||||
| kernel/FS/VirtualFileSystem.o	\ | ||||
| kernel/Input.o					\ | ||||
| kernel/Input/PS2Controller.o	\ | ||||
| kernel/Input/PS2Keyboard.o		\ | ||||
| kernel/Input/PS2Keymap.o		\ | ||||
| kernel/InterruptController.o	\ | ||||
| kernel/kernel.o					\ | ||||
| kernel/kmalloc.o				\ | ||||
|  | @ -113,6 +116,7 @@ always: | |||
| 	mkdir -p $(BUILDDIR)/$(ARCHDIR) | ||||
| 	mkdir -p $(BUILDDIR)/kernel | ||||
| 	mkdir -p $(BUILDDIR)/kernel/FS | ||||
| 	mkdir -p $(BUILDDIR)/kernel/Input | ||||
| 	mkdir -p $(BUILDDIR)/kernel/Storage | ||||
| 	mkdir -p $(BUILDDIR)/userspace | ||||
| 	mkdir -p $(BUILDDIR)/font | ||||
|  |  | |||
|  | @ -21,6 +21,65 @@ namespace Kernel | |||
| 			uint32_t creator_revision; | ||||
| 		} __attribute__((packed)); | ||||
| 
 | ||||
| 		struct FADT : public SDTHeader | ||||
| 		{ | ||||
| 			uint32_t firmware_ctrl; | ||||
| 			uint32_t dsdt; | ||||
| 			uint8_t __reserved; | ||||
| 			uint8_t preferred_pm_profile; | ||||
| 			uint16_t sci_int; | ||||
| 			uint32_t smi_cmd; | ||||
| 			uint8_t acpi_enable; | ||||
| 			uint8_t acpi_disable; | ||||
| 			uint8_t s4bios_req; | ||||
| 			uint8_t pstate_cnt; | ||||
| 			uint32_t pm1a_evt_blk; | ||||
| 			uint32_t pm1b_evt_blk; | ||||
| 			uint32_t pm1a_cnt_blk; | ||||
| 			uint32_t pm1b_cnt_blk; | ||||
| 			uint32_t pm2_cnt_blk; | ||||
| 			uint32_t pm_tmr_blk; | ||||
| 			uint32_t gpe0_blk; | ||||
| 			uint32_t gpe1_blk; | ||||
| 			uint8_t pm1_evt_len; | ||||
| 			uint8_t pm1_cnt_len; | ||||
| 			uint8_t pm2_cnt_len; | ||||
| 			uint8_t pm_tmr_len; | ||||
| 			uint8_t gpe0_blk_len; | ||||
| 			uint8_t gpe1_blk_len; | ||||
| 			uint8_t gpe1_base; | ||||
| 			uint8_t cst_cnt; | ||||
| 			uint16_t p_lvl2_lat; | ||||
| 			uint16_t p_lvl3_lat; | ||||
| 			uint16_t flush_size; | ||||
| 			uint16_t flush_stride; | ||||
| 			uint8_t duty_offset; | ||||
| 			uint8_t duty_width; | ||||
| 			uint8_t day_alrm; | ||||
| 			uint8_t mon_alrm; | ||||
| 			uint8_t century; | ||||
| 			uint16_t iapc_boot_arch; | ||||
| 			uint8_t __reserved2; | ||||
| 			uint32_t flags; | ||||
| 			uint8_t reset_reg[12]; | ||||
| 			uint8_t reset_value; | ||||
| 			uint16_t arm_boot_arch; | ||||
| 			uint8_t fadt_minor_version; | ||||
| 			uint64_t x_firmware_version; | ||||
| 			uint64_t x_dsdt; | ||||
| 			uint8_t x_pm1a_evt_blk[12]; | ||||
| 			uint8_t x_pm1b_evt_blk[12]; | ||||
| 			uint8_t x_pm1a_cnt_blk[12]; | ||||
| 			uint8_t x_pm1b_cnt_blk[12]; | ||||
| 			uint8_t x_pm2_cnt_blk[12]; | ||||
| 			uint8_t x_pm_tmr_blk[12]; | ||||
| 			uint8_t x_gpe0_blk[12]; | ||||
| 			uint8_t x_gpe1_blk[12]; | ||||
| 			uint8_t sleep_control_reg[12]; | ||||
| 			uint8_t sleep_status_reg[12]; | ||||
| 			uint64_t hypervison_vendor_identity; | ||||
| 		} __attribute__((packed)); | ||||
| 
 | ||||
| 	public: | ||||
| 		static BAN::ErrorOr<void> initialize(); | ||||
| 		static ACPI& get(); | ||||
|  |  | |||
|  | @ -0,0 +1,59 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/Vector.h> | ||||
| #include <kernel/SpinLock.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	class Device | ||||
| 	{ | ||||
| 	public: | ||||
| 		enum class Type | ||||
| 		{ | ||||
| 			BlockDevice, | ||||
| 			CharacterDevice, | ||||
| 			DeviceController | ||||
| 		}; | ||||
| 
 | ||||
| 		virtual ~Device() {} | ||||
| 		virtual Type type() const = 0; | ||||
| 		virtual void update() {} | ||||
| 	}; | ||||
| 
 | ||||
| 	class BlockDevice : public Device | ||||
| 	{ | ||||
| 	public: | ||||
| 		virtual Type type() const override { return Type::BlockDevice; } | ||||
| 	}; | ||||
| 
 | ||||
| 	class CharacterDevice : public Device | ||||
| 	{ | ||||
| 	public: | ||||
| 		virtual Type type() const override { return Type::CharacterDevice; } | ||||
| 
 | ||||
| 		virtual BAN::ErrorOr<void> read(BAN::Span<uint8_t>); | ||||
| 	}; | ||||
| 
 | ||||
| 	class DeviceManager | ||||
| 	{ | ||||
| 		BAN_NON_COPYABLE(DeviceManager); | ||||
| 		BAN_NON_MOVABLE(DeviceManager); | ||||
| 
 | ||||
| 	public: | ||||
| 		static DeviceManager& get(); | ||||
| 
 | ||||
| 		void update(); | ||||
| 		void add_device(Device*); | ||||
| 
 | ||||
| 		BAN::Vector<Device*> devices() { return m_devices; } | ||||
| 
 | ||||
| 	private: | ||||
| 		DeviceManager() = default; | ||||
| 
 | ||||
| 	private: | ||||
| 		SpinLock m_lock; | ||||
| 		BAN::Vector<Device*> m_devices; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -1,67 +0,0 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/Function.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| namespace Input | ||||
| { | ||||
| 
 | ||||
| 	enum class Key : uint8_t | ||||
| 	{ | ||||
| 		INVALID, None, | ||||
| 		_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, | ||||
| 		A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, | ||||
| 		A_Dot, A_Dots, O_Dots, | ||||
| 
 | ||||
| 		Comma, Colon, Period, Semicolon, Hyphen, Underscore, SingleQuote, Asterix, Caret, Tilde, | ||||
| 		ExclamationMark, QuestionMark, DoubleQuote, Hashtag, Percent, Ampersand, Slash, BackSlash, Plus, Equals, | ||||
| 		OpenParen, CloseParen, OpenBracket, CloseBracket, OpenBrace, CloseBrace, | ||||
| 		Dollar, Pound, Euro, Currency, Enter, Space, Tab, Backspace, LessThan, MoreThan, Tick, BackTick, Section, Half, At, Pipe, | ||||
| 		End, Home, Insert, Delete, Super, PageUp, PageDown, PrintScreen, Left, Right, Up, Down, | ||||
| 
 | ||||
| 		LeftShift, RightShift, CapsLock, LeftCtrl, RightCtrl, LeftAlt, RightAlt, NumLock, ScrollLock, Escape, | ||||
| 
 | ||||
| 		Numpad0, Numpad1, Numpad2, Numpad3, Numpad4, Numpad5, Numpad6, Numpad7, Numpad8, Numpad9, | ||||
| 		NumpadSep, NumpadPlus, NumpadMult, NumpadDiv, NumpadMinus, NumpadEnter, | ||||
| 
 | ||||
| 		Mute, VolumeDown, VolumeUp, Calculator, PlayPause, Stop, PreviousTrack, NextTrack, | ||||
| 
 | ||||
| 		F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, | ||||
| 
 | ||||
| 		Count | ||||
| 	}; | ||||
| 
 | ||||
| 	struct KeyEvent | ||||
| 	{ | ||||
| 		Key		key; | ||||
| 		uint8_t	modifiers; | ||||
| 		bool	pressed; | ||||
| 	}; | ||||
| 
 | ||||
| 	enum class MouseButton | ||||
| 	{ | ||||
| 		Left, Right, Middle, | ||||
| 	}; | ||||
| 	struct MouseButtonEvent | ||||
| 	{ | ||||
| 		MouseButton button; | ||||
| 	}; | ||||
| 
 | ||||
| 	struct MouseMoveEvent | ||||
| 	{ | ||||
| 		int16_t dx; | ||||
| 		int16_t dy; | ||||
| 	}; | ||||
| 	 | ||||
| 
 | ||||
| 	bool initialize(); | ||||
| 	void update(); | ||||
| 	bool is_key_down(Key); | ||||
| 
 | ||||
| 	void register_key_event_callback(const BAN::Function<void(KeyEvent)>&); | ||||
| 	void register_mouse_button_event_callback(const BAN::Function<void(MouseButtonEvent)>&); | ||||
| 	void register_mouse_move_event_callback(const BAN::Function<void(MouseMoveEvent)>&); | ||||
| 
 | ||||
| 	const char* key_event_to_utf8(KeyEvent); | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,99 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| namespace Kernel::Input | ||||
| { | ||||
| 
 | ||||
| 	enum class Key | ||||
| 	{ | ||||
| 		Invalid, None, | ||||
| 		A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, | ||||
| 		A_Ring, A_Umlaut, O_Umlaut, | ||||
| 		_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, | ||||
| 		F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, | ||||
| 		Insert, PrintScreen, Delete, Home, End, PageUp, PageDown, Enter, Space, | ||||
| 		ExclamationMark, DoubleQuote, Hashtag, Currency, Percent, Ampersand, Slash, Section, Half, | ||||
| 		OpenBracet, CloseBracet, OpenBrace, CloseBrace, OpenCurlyBrace, CloseCurlyBrace, | ||||
| 		Equals, QuestionMark, Plus, BackSlash, Acute, BackTick, TwoDots, Backspace, AtSign, Pound, Dollar, Euro, | ||||
| 		Escape, Tab, CapsLock, LeftShift, LeftCtrl, Super, Alt, AltGr, RightCtrl, RightShift, | ||||
| 		SingleQuote, Asterix, Caret, Tilde, ArrowUp, ArrowDown, ArrowLeft, ArrowRight, | ||||
| 		Comma, Semicolon, Period, Colon, Hyphen, Underscore, NumLock, ScrollLock, LessThan, GreaterThan, Pipe, | ||||
| 		Numpad0, Numpad1, Numpad2, Numpad3, Numpad4, Numpad5, Numpad6, Numpad7, Numpad8, Numpad9, | ||||
| 		NumpadPlus, NumpadMinus, NumpadMultiply, NumpadDivide, NumpadEnter, NumpadDecimal, | ||||
| 		VolumeMute, VolumeUp, VolumeDown, Calculator, MediaPlayPause, MediaStop, MediaPrevious, MediaNext, | ||||
| 		Count, | ||||
| 	}; | ||||
| 
 | ||||
| 	struct KeyEvent | ||||
| 	{ | ||||
| 		enum class Modifier : uint8_t | ||||
| 		{ | ||||
| 			Shift		= (1 << 0), | ||||
| 			Ctrl		= (1 << 1), | ||||
| 			Alt			= (1 << 2), | ||||
| 			AltGr		= (1 << 3), | ||||
| 			CapsLock	= (1 << 4), | ||||
| 			NumLock		= (1 << 5), | ||||
| 			ScrollLock	= (1 << 6), | ||||
| 			Released	= (1 << 7), | ||||
| 		}; | ||||
| 
 | ||||
| 		bool shift()		const { return modifier & (uint8_t)Modifier::Shift; } | ||||
| 		bool ctrl()			const { return modifier & (uint8_t)Modifier::Ctrl; } | ||||
| 		bool alt()			const { return modifier & (uint8_t)Modifier::Alt; } | ||||
| 		bool altgr()		const { return modifier & (uint8_t)Modifier::AltGr; } | ||||
| 		bool caps_lock()	const { return modifier & (uint8_t)Modifier::CapsLock; } | ||||
| 		bool num_lock()		const { return modifier & (uint8_t)Modifier::NumLock; } | ||||
| 		bool scroll_lock()	const { return modifier & (uint8_t)Modifier::ScrollLock; } | ||||
| 		bool released()		const { return modifier & (uint8_t)Modifier::Released; } | ||||
| 		bool pressed()		const { return !released(); } | ||||
| 
 | ||||
| 		uint8_t modifier; | ||||
| 		Key key; | ||||
| 	}; | ||||
| 
 | ||||
| 	inline const char* key_event_to_utf8(KeyEvent event) | ||||
| 	{ | ||||
| 		static constexpr const char* utf8_lower[] = { | ||||
| 			nullptr, nullptr, | ||||
| 			"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", | ||||
| 			"å", "ä", "ö", | ||||
| 			"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", | ||||
| 			nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | ||||
| 			nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, " ", | ||||
| 			"!", "\"", "#", "¤", "%", "&", "/", "§", "½", | ||||
| 			"(", ")", "[", "]", "{", "}", | ||||
| 			"=", "?", "+", "\\", "´", "`", "¨", nullptr, "@", "£", "$", "€", | ||||
| 			nullptr, "\t", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | ||||
| 			"'", "*", "^", "~", nullptr, nullptr, nullptr, nullptr, | ||||
| 			",", ";", ".", ":", "-", "_", nullptr, nullptr, "<", ">", "|", | ||||
| 			"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", | ||||
| 			"+", "-", "*", "/", nullptr, ",", | ||||
| 			nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | ||||
| 		}; | ||||
| 		static_assert((size_t)Key::Count == sizeof(utf8_lower) / sizeof(*utf8_lower)); | ||||
| 
 | ||||
| 		static constexpr const char* utf8_upper[] = { | ||||
| 			nullptr, nullptr, | ||||
| 			"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", | ||||
| 			"Å", "Ä", "Ö", | ||||
| 			"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", | ||||
| 			nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | ||||
| 			nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, " ", | ||||
| 			"!", "\"", "#", "¤", "%", "&", "/", "§", "½", | ||||
| 			"(", ")", "[", "]", "{", "}", | ||||
| 			"=", "?", "+", "\\", "´", "`", "¨", nullptr, "@", "£", "$", "€", | ||||
| 			nullptr, "\t", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | ||||
| 			"'", "*", "^", "~", nullptr, nullptr, nullptr, nullptr, | ||||
| 			",", ";", ".", ":", "-", "_", nullptr, nullptr, "<", ">", "|", | ||||
| 			"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", | ||||
| 			"+", "-", "*", "/", nullptr, ",", | ||||
| 			nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | ||||
| 		}; | ||||
| 		static_assert((size_t)Key::Count == sizeof(utf8_upper) / sizeof(*utf8_lower)); | ||||
| 
 | ||||
| 		return (event.shift() ^ event.caps_lock()) ? utf8_upper[(uint8_t)event.key] : utf8_lower[(uint8_t)event.key]; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,38 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <kernel/Device.h> | ||||
| 
 | ||||
| namespace Kernel::Input | ||||
| { | ||||
| 
 | ||||
| 	class PS2Device : public CharacterDevice | ||||
| 	{ | ||||
| 	public: | ||||
| 		virtual ~PS2Device() {} | ||||
| 		virtual void on_byte(uint8_t) = 0; | ||||
| 	}; | ||||
| 
 | ||||
| 	class PS2Controller | ||||
| 	{ | ||||
| 	public: | ||||
| 		static BAN::ErrorOr<void> initialize(); | ||||
| 		static PS2Controller& get(); | ||||
| 
 | ||||
| 		void send_byte(const 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); | ||||
| 
 | ||||
| 		static void device0_irq(); | ||||
| 		static void device1_irq(); | ||||
| 
 | ||||
| 	private: | ||||
| 		PS2Device* m_devices[2] { nullptr, nullptr }; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,64 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/CircularQueue.h> | ||||
| #include <kernel/Input/KeyEvent.h> | ||||
| #include <kernel/Input/PS2Controller.h> | ||||
| #include <kernel/Input/PS2Keymap.h> | ||||
| 
 | ||||
| namespace Kernel::Input | ||||
| { | ||||
| 
 | ||||
| 	class PS2Keyboard final : public PS2Device | ||||
| 	{ | ||||
| 	private: | ||||
| 		enum Command : uint8_t | ||||
| 		{ | ||||
| 			SET_LEDS = 0xED, | ||||
| 			SCANCODE = 0xF0, | ||||
| 			ENABLE_SCANNING = 0xF4, | ||||
| 			DISABLE_SCANNING = 0xF5, | ||||
| 		}; | ||||
| 
 | ||||
| 		enum class State | ||||
| 		{ | ||||
| 			Normal, | ||||
| 			WaitingAck, | ||||
| 		}; | ||||
| 
 | ||||
| 	public: | ||||
| 		static BAN::ErrorOr<PS2Keyboard*> create(PS2Controller&); | ||||
| 
 | ||||
| 		virtual void on_byte(uint8_t) override; | ||||
| 		virtual void update() override; | ||||
| 
 | ||||
| 		virtual BAN::ErrorOr<void> read(BAN::Span<uint8_t>) override; | ||||
| 
 | ||||
| 	private: | ||||
| 		PS2Keyboard(PS2Controller& controller) | ||||
| 			: m_controller(controller) | ||||
| 		{} | ||||
| 		BAN::ErrorOr<void> initialize(); | ||||
| 
 | ||||
| 		void append_command_queue(uint8_t); | ||||
| 		void append_command_queue(uint8_t, uint8_t); | ||||
| 
 | ||||
| 		void buffer_has_key(); | ||||
| 
 | ||||
| 		void update_leds(); | ||||
| 
 | ||||
| 	private: | ||||
| 		PS2Controller& m_controller; | ||||
| 		uint8_t m_byte_buffer[10]; | ||||
| 		uint8_t m_byte_index { 0 }; | ||||
| 
 | ||||
| 		uint8_t m_modifiers { 0 }; | ||||
| 
 | ||||
| 		BAN::CircularQueue<KeyEvent, 10> m_event_queue; | ||||
| 		BAN::CircularQueue<uint8_t, 10> m_command_queue; | ||||
| 
 | ||||
| 		PS2Keymap m_keymap; | ||||
| 
 | ||||
| 		State m_state { State::Normal }; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,23 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/Vector.h> | ||||
| #include <kernel/Input/KeyEvent.h> | ||||
| 
 | ||||
| namespace Kernel::Input | ||||
| { | ||||
| 
 | ||||
| 	class PS2Keymap | ||||
| 	{ | ||||
| 	public: | ||||
| 		PS2Keymap(); | ||||
| 
 | ||||
| 		Key key_for_scancode_and_modifiers(uint32_t, uint8_t); | ||||
| 
 | ||||
| 	private: | ||||
| 		BAN::Vector<Key> m_normal_keymap; | ||||
| 		BAN::Vector<Key> m_shift_keymap; | ||||
| 		BAN::Vector<Key> m_altgr_keymap; | ||||
| 		BAN::Vector<Key> m_extended_keymap; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -2,7 +2,7 @@ | |||
| 
 | ||||
| #include <BAN/String.h> | ||||
| #include <BAN/Vector.h> | ||||
| #include <kernel/Input.h> | ||||
| #include <kernel/Input/KeyEvent.h> | ||||
| #include <kernel/TTY.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
|  |  | |||
|  | @ -0,0 +1,26 @@ | |||
| #include <kernel/Device.h> | ||||
| #include <kernel/LockGuard.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	DeviceManager& DeviceManager::get() | ||||
| 	{ | ||||
| 		static DeviceManager instance; | ||||
| 		return instance; | ||||
| 	} | ||||
| 
 | ||||
| 	void DeviceManager::update() | ||||
| 	{ | ||||
| 		LockGuard _(m_lock); | ||||
| 		for (Device* device : m_devices) | ||||
| 			device->update(); | ||||
| 	} | ||||
| 
 | ||||
| 	void DeviceManager::add_device(Device* device) | ||||
| 	{ | ||||
| 		LockGuard _(m_lock); | ||||
| 		MUST(m_devices.push_back(device)); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -1,690 +0,0 @@ | |||
| #include <BAN/Queue.h> | ||||
| #include <kernel/Debug.h> | ||||
| #include <kernel/IDT.h> | ||||
| #include <kernel/Input.h> | ||||
| #include <kernel/InterruptController.h> | ||||
| #include <kernel/IO.h> | ||||
| #include <kernel/kprint.h> | ||||
| #include <kernel/PIT.h> | ||||
| 
 | ||||
| #include <kernel/KeyboardLayout/FI.h> | ||||
| 
 | ||||
| #define DEBUG_ALL_IRQ 0 | ||||
| #define KEYBOARD_SHOW_UNKNOWN 1 | ||||
| 
 | ||||
| #define MOUSE_ENABLED 0 | ||||
| 
 | ||||
| #define I8042_DATA_PORT				0x60 | ||||
| #define I8042_STATUS_REGISTER		0x64 | ||||
| #define I8042_COMMAND_REGISTER		0x64 | ||||
| 
 | ||||
| #define I8042_STATUS_OUT_FULL		(1 << 0) | ||||
| #define I8042_STATUS_IN_FULL		(1 << 1) | ||||
| 
 | ||||
| #define I8042_READ_CONFIG			0x20 | ||||
| #define I8042_WRITE_CONFIG			0x60 | ||||
| 
 | ||||
| #define I8042_CONFING_IRQ_FIRST		(1 << 0) | ||||
| #define I8042_CONFING_IRQ_SECOND	(1 << 1) | ||||
| #define I8042_CONFING_DUAL_CHANNEL	(1 << 5) | ||||
| #define I8042_CONFING_TRANSLATION	(1 << 6) | ||||
| 
 | ||||
| #define I8042_ENABLE_FIRST_PORT		0xAE | ||||
| #define I8042_ENABLE_SECOND_PORT	0xA8 | ||||
| #define I8042_DISABLE_FIRST_PORT	0xAD | ||||
| #define I8042_DISABLE_SECOND_PORT	0xA7 | ||||
| 
 | ||||
| #define I8042_TEST_CONTROLLER		0xAA | ||||
| #define I8042_TEST_CONTROLLER_PASS	0x55 | ||||
| 
 | ||||
| #define I8042_TEST_FIRST_PORT		0xAB | ||||
| #define I8042_TEST_FIRST_PORT_PASS	0x00 | ||||
| 
 | ||||
| #define I8042_TEST_SECOND_PORT		0xA9 | ||||
| #define I8042_TEST_SECOND_PORT_PASS 0x00 | ||||
| 
 | ||||
| #define I8042_KB_ACK				0xFA | ||||
| #define I8042_KB_RESEND				0xFE | ||||
| #define I8042_KB_RESET				0xFF | ||||
| #define I8042_KB_SELF_TEST_PASS		0xAA | ||||
| #define I8042_KB_SET_SCAN_CODE_SET	0xF0 | ||||
| #define I8042_KB_SET_LEDS			0xED | ||||
| #define I8042_KB_LED_SCROLL_LOCK	(1 << 0) | ||||
| #define I8042_KB_LED_NUM_LOCK		(1 << 1) | ||||
| #define I8042_KB_LED_CAPS_LOCK		(1 << 2) | ||||
| 
 | ||||
| #define I8042_MOUSE_ACK				0xFA | ||||
| #define I8042_MOUSE_RESET			0xFF | ||||
| #define I8042_MOUSE_SELF_TEST_PASS	0xAA | ||||
| #define I8042_MOUSE_ENABLE			0xF4 | ||||
| #define I8042_MOUSE_DISABLE			0xF5 | ||||
| 
 | ||||
| #define I8042_TIMEOUT_MS			1000 | ||||
| 
 | ||||
| #define KEYBOARD_IRQ				0x01 | ||||
| #define MOUSE_IRQ					0x0C | ||||
| 
 | ||||
| #define TARGET_KEYBOARD				1 | ||||
| #define TARGET_MOUSE				2 | ||||
| 
 | ||||
| #define MOD_ALT		(1 << 0) | ||||
| #define MOD_CTRL	(1 << 1) | ||||
| #define MOD_SHIFT	(1 << 2) | ||||
| #define MOD_ALTGR	(1 << 3) | ||||
| #define MOD_CAPS	(1 << 4) | ||||
| 
 | ||||
| namespace Input | ||||
| { | ||||
| 
 | ||||
| 	static bool s_keyboard_state[0xFF] = {}; | ||||
| 
 | ||||
| 	struct Command | ||||
| 	{ | ||||
| 		uint8_t target		= 0; | ||||
| 		uint8_t	command		= 0; | ||||
| 		uint8_t	data		= 0; | ||||
| 		bool	has_data	= false; | ||||
| 		uint8_t	resp_cnt	= 0; | ||||
| 		uint8_t	_sent		= 0; | ||||
| 		uint8_t _ack		= 0; | ||||
| 		bool	_done		= false; | ||||
| 	}; | ||||
| 	static uint64_t				s_command_sent = 0; | ||||
| 	static BAN::Queue<Command>	s_command_queue; | ||||
| 	static uint8_t				s_command_response[3] = {}; | ||||
| 	static uint8_t				s_command_response_index = 0; | ||||
| 
 | ||||
| 	static BAN::Queue<KeyEvent> s_key_event_queue; | ||||
| 	static uint8_t s_keyboard_key_buffer[10] = {}; | ||||
| 	static uint8_t s_keyboard_key_buffer_size = 0; | ||||
| 
 | ||||
| 	static BAN::Queue<MouseButtonEvent> s_mouse_button_event_queue; | ||||
| 	static BAN::Queue<MouseMoveEvent> s_mouse_move_event_queue; | ||||
| 	static uint8_t s_mouse_data_buffer[3] = {}; | ||||
| 	static uint8_t s_mouse_data_buffer_index = 0; | ||||
| 
 | ||||
| 	static uint8_t s_led_states	= 0b000; | ||||
| 	static uint8_t s_modifiers	= 0x00; | ||||
| 
 | ||||
| 	static BAN::Function<void(KeyEvent)> s_key_event_callback; | ||||
| 	static BAN::Function<void(MouseButtonEvent)> s_mouse_button_event_callback; | ||||
| 	static BAN::Function<void(MouseMoveEvent)> s_mouse_move_event_callback; | ||||
| 
 | ||||
| 	static const char* s_key_to_utf8_lower[] | ||||
| 	{ | ||||
| 		nullptr, nullptr, | ||||
| 		"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", | ||||
| 		"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", | ||||
| 		"å", "ä", "ö", | ||||
| 
 | ||||
| 		",", ":", ".", ";", "-", "_", "'", "*", "^", "~", | ||||
| 		"!", "?", "\"", "#", "%", "&", "/", "\\", "+", "=", | ||||
| 		"(", ")", "[", "]", "{", "}", | ||||
| 		"$", "£", "€", "¤", "\n", " ", "\t", nullptr, "<", ">", "´", "`", "§", "½", "@", "|", | ||||
| 		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | ||||
| 
 | ||||
| 		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | ||||
| 
 | ||||
| 		"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", | ||||
| 		",", "+", "*", "/", "-", "\n", | ||||
| 
 | ||||
| 		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | ||||
|   | ||||
| 		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | ||||
| 	}; | ||||
| 	static_assert(sizeof(s_key_to_utf8_lower) == (int)Key::Count * sizeof(*s_key_to_utf8_lower)); | ||||
| 
 | ||||
| 	static const char* s_key_to_utf8_upper[] | ||||
| 	{ | ||||
| 		nullptr, nullptr, | ||||
| 		"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", | ||||
| 		"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", | ||||
| 		"Å", "Ä", "Ö", | ||||
| 
 | ||||
| 		",", ":", ".", ";", "-", "_", "'", "*", "^", "~", | ||||
| 		"!", "?", "\"", "#", "%", "&", "/", "\\", "+", "=", | ||||
| 		"(", ")", "[", "]", "{", "}", | ||||
| 		"$", "£", "€", "¤", "\n", " ", "\t", nullptr, "<", ">", "´", "`", "§", "½", "@", "|", | ||||
| 		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | ||||
| 
 | ||||
| 		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | ||||
| 
 | ||||
| 		"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", | ||||
| 		",", "+", "*", "/", "-", "\n", | ||||
| 
 | ||||
| 		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | ||||
|   | ||||
| 		nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, | ||||
| 	}; | ||||
| 	static_assert(sizeof(s_key_to_utf8_upper) == (int)Key::Count * sizeof(*s_key_to_utf8_upper)); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 	static void keyboard_new_key(); | ||||
| 
 | ||||
| 
 | ||||
| 	static uint8_t wait_and_read() | ||||
| 	{ | ||||
| 		while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_OUT_FULL) == 0) | ||||
| 			continue; | ||||
| 		return IO::inb(I8042_DATA_PORT); | ||||
| 	} | ||||
| 
 | ||||
| 	static void i8042_controller_command(uint8_t command) | ||||
| 	{ | ||||
| 		IO::outb(I8042_COMMAND_REGISTER, command); | ||||
| 	} | ||||
| 
 | ||||
| 	static void i8042_controller_command(uint8_t command, uint8_t data) | ||||
| 	{ | ||||
| 		IO::outb(I8042_COMMAND_REGISTER, command); | ||||
| 		while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_IN_FULL) != 0) | ||||
| 			continue; | ||||
| 		IO::outb(I8042_DATA_PORT, data); | ||||
| 	} | ||||
| 
 | ||||
| 	static bool i8042_command(uint8_t target, uint8_t command) | ||||
| 	{ | ||||
| 		if (target == TARGET_MOUSE) | ||||
| 			IO::outb(I8042_COMMAND_REGISTER, 0xD4);	 | ||||
| 
 | ||||
| 		auto timeout = PIT::ms_since_boot() + I8042_TIMEOUT_MS; | ||||
| 
 | ||||
| 		while (PIT::ms_since_boot() < timeout) | ||||
| 		{ | ||||
| 			if ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_IN_FULL) == 0) | ||||
| 			{ | ||||
| 				IO::outb(I8042_DATA_PORT, command); | ||||
| 				s_command_sent = PIT::ms_since_boot(); | ||||
| 				return true; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	static void i8042_handle_byte(uint8_t target, uint8_t raw) | ||||
| 	{ | ||||
| 		bool waiting_response = false; | ||||
| 
 | ||||
| 		if (!s_command_queue.empty()) | ||||
| 		{ | ||||
| 			auto& command = s_command_queue.front(); | ||||
| 			if (command.target == target && command._sent && !command._done) | ||||
| 				waiting_response = true; | ||||
| 		} | ||||
| 
 | ||||
| 		if (target == TARGET_KEYBOARD) | ||||
| 		{ | ||||
| 			if (waiting_response) | ||||
| 			{ | ||||
| 				auto& command = s_command_queue.front(); | ||||
| 
 | ||||
| 				if (raw == I8042_KB_RESEND) | ||||
| 				{ | ||||
| 					dprintln("PS/2 Keyboard: Resend 0x{H}", command._sent == 2 ? command.data : command.command); | ||||
| 					command._sent--; | ||||
| 				} | ||||
| 				else if (raw == I8042_KB_ACK) | ||||
| 				{ | ||||
| 					command._ack++; | ||||
| 					if (command.resp_cnt == 0) | ||||
| 						command._done = (command._ack >= (1 + command.has_data)); | ||||
| 				} | ||||
| 				else if (raw == 0x00) | ||||
| 				{ | ||||
| 					dprintln("\e[33mKey detection error or internal buffer overrun\e[m"); | ||||
| 					command._sent = 0; | ||||
| 					command._ack = 0; | ||||
| 					command._done = false; | ||||
| 					s_command_response_index = 0; | ||||
| 				} | ||||
| 				else if (raw == 0xEE && command.command == 0xEE) | ||||
| 				{ | ||||
| 					s_command_queue.pop(); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					s_command_response[s_command_response_index++] = raw; | ||||
| 					if (s_command_response_index >= command.resp_cnt) | ||||
| 						command._done = true; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				s_keyboard_key_buffer[s_keyboard_key_buffer_size++] = raw; | ||||
| 				if (raw != 0xE0) | ||||
| 					keyboard_new_key(); | ||||
| 			} | ||||
| 		} | ||||
| 		else if (target == TARGET_MOUSE) | ||||
| 		{ | ||||
| 			if (waiting_response) | ||||
| 			{ | ||||
| 				auto& command = s_command_queue.front(); | ||||
| 
 | ||||
| 				if (raw == I8042_MOUSE_ACK) | ||||
| 				{ | ||||
| 					command._ack++; | ||||
| 					if (command.resp_cnt == 0) | ||||
| 						command._done = (command._ack >= (1 + command.has_data)); | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					s_command_response[s_command_response_index++] = raw; | ||||
| 					if (s_command_response_index >= command.resp_cnt) | ||||
| 						command._done = true; | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				s_mouse_data_buffer[s_mouse_data_buffer_index++] = raw; | ||||
| 
 | ||||
| 				if (s_mouse_data_buffer_index >= 3) | ||||
| 				{ | ||||
| 					if (s_mouse_data_buffer[0] & 0x07) | ||||
| 					{ | ||||
| 						bool left   = s_mouse_data_buffer[0] & (1 << 0); | ||||
| 						bool right  = s_mouse_data_buffer[0] & (1 << 1); | ||||
| 						bool middle = s_mouse_data_buffer[0] & (1 << 2); | ||||
| 
 | ||||
| 						if (left)	MUST(s_mouse_button_event_queue.push({ .button = MouseButton::Left })); | ||||
| 						if (right)	MUST(s_mouse_button_event_queue.push({ .button = MouseButton::Right })); | ||||
| 						if (middle)	MUST(s_mouse_button_event_queue.push({ .button = MouseButton::Middle })); | ||||
| 					} | ||||
| 
 | ||||
| 					if (s_mouse_data_buffer[1] || s_mouse_data_buffer[2]) | ||||
| 					{ | ||||
| 						int16_t rel_x = (int16_t)s_mouse_data_buffer[1] - ((s_mouse_data_buffer[0] << 4) & 0x100); | ||||
| 						int16_t rel_y = (int16_t)s_mouse_data_buffer[2] - ((s_mouse_data_buffer[0] << 3) & 0x100); | ||||
| 
 | ||||
| 						MUST(s_mouse_move_event_queue.push({ .dx = rel_x, .dy = rel_y })); | ||||
| 					}		 | ||||
| 
 | ||||
| 					s_mouse_data_buffer_index = 0; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			Kernel::panic("Unknown target"); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	void update() | ||||
| 	{ | ||||
| 		if (!s_command_queue.empty()) | ||||
| 		{ | ||||
| 			auto& command = s_command_queue.front(); | ||||
| 			if (command.target != TARGET_KEYBOARD && command.target != TARGET_MOUSE) | ||||
| 				Kernel::panic("Undefined target for command 0x{2H}", command.command); | ||||
| 
 | ||||
| 			if (command._sent == 0 && command._ack == 0) | ||||
| 			{ | ||||
| 				command._sent++; | ||||
| 				if (!i8042_command(command.target, command.command)) | ||||
| 					Kernel::panic("PS/2 command oof {}, 0x{2H}", command.target, command.command); | ||||
| 			} | ||||
| 
 | ||||
| 			if (command._sent == 1 && command._ack == 1 && command.has_data) | ||||
| 			{ | ||||
| 				command._sent++; | ||||
| 				if (!i8042_command(command.target, command.data)) | ||||
| 					Kernel::panic("PS/2 data oof {}, 0x{2H}", command.target, command.data); | ||||
| 			} | ||||
| 			 | ||||
| 			if (command._sent > 0 && PIT::ms_since_boot() > s_command_sent + 1000) | ||||
| 			{ | ||||
| 				dprintln("PS/2 command 0x{2H} timed out on {}", command.command, command.target); | ||||
| 				// Discard command on timeout? 
 | ||||
| 				command._done = true; | ||||
| 				command.target = 0; | ||||
| 			} | ||||
| 
 | ||||
| 			if (command._done) | ||||
| 			{ | ||||
| 				if (command.target == TARGET_KEYBOARD) | ||||
| 				{ | ||||
| 					switch (command.command) | ||||
| 					{ | ||||
| 						case I8042_KB_RESET: | ||||
| 							if (s_command_response[0] != I8042_KB_SELF_TEST_PASS) | ||||
| 								Kernel::panic("PS/2 Keyboard self test failed"); | ||||
| 							break; | ||||
| 						case I8042_KB_SET_SCAN_CODE_SET: | ||||
| 							break; | ||||
| 						case I8042_KB_SET_LEDS: | ||||
| 							break; | ||||
| 						default: | ||||
| 							Kernel::panic("PS/2 Keyboard unhandled command"); | ||||
| 					} | ||||
| 				} | ||||
| 				else if (command.target == TARGET_MOUSE) | ||||
| 				{ | ||||
| 					switch (command.command) | ||||
| 					{ | ||||
| 						case I8042_MOUSE_RESET: | ||||
| 							if (s_command_response[0] != I8042_MOUSE_SELF_TEST_PASS) | ||||
| 								Kernel::panic("PS/2 Mouse self test failed"); | ||||
| 							if (s_command_response[1] != 0x00) | ||||
| 								Kernel::panic("PS/2 Mouse invalid byte sent after self test"); | ||||
| 							break; | ||||
| 						case I8042_MOUSE_ENABLE: | ||||
| 							break; | ||||
| 						case I8042_MOUSE_DISABLE: | ||||
| 							break; | ||||
| 						default: | ||||
| 							Kernel::panic("PS/2 Mouse unhandled command"); | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				s_command_response_index = 0; | ||||
| 				s_command_queue.pop(); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		while (!s_key_event_queue.empty()) | ||||
| 		{ | ||||
| 			if (s_key_event_callback) | ||||
| 				s_key_event_callback(s_key_event_queue.front()); | ||||
| 			s_key_event_queue.pop(); | ||||
| 		} | ||||
| 
 | ||||
| 		while (!s_mouse_button_event_queue.empty()) | ||||
| 		{ | ||||
| 			if (s_mouse_button_event_callback) | ||||
| 				s_mouse_button_event_callback(s_mouse_button_event_queue.front()); | ||||
| 			s_mouse_button_event_queue.pop(); | ||||
| 		} | ||||
| 
 | ||||
| 		while (!s_mouse_move_event_queue.empty()) | ||||
| 		{ | ||||
| 			if (s_mouse_move_event_callback) | ||||
| 				s_mouse_move_event_callback(s_mouse_move_event_queue.front()); | ||||
| 			s_mouse_move_event_queue.pop(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	bool is_key_down(Key key) | ||||
| 	{ | ||||
| 		return s_keyboard_state[(int)key]; | ||||
| 	} | ||||
| 
 | ||||
| 	static void keyboard_new_key() | ||||
| 	{ | ||||
| 		uint8_t index = 0; | ||||
| 		bool extended = (s_keyboard_key_buffer[index] == 0xE0); | ||||
| 		if (extended) | ||||
| 			index++; | ||||
| 		 | ||||
| 		bool pressed = (s_keyboard_key_buffer[index] & 0x80) == 0; | ||||
| 		uint8_t ch = s_keyboard_key_buffer[index] & ~0x80; | ||||
| 
 | ||||
| 		Key key = Key::INVALID; | ||||
| 
 | ||||
| 		if (extended) | ||||
| 		{ | ||||
| 			key = scan_code_to_key_extended[ch]; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if (s_modifiers & MOD_SHIFT) | ||||
| 				key = scan_code_to_key_shift[ch]; | ||||
| 			else if (s_modifiers & MOD_ALTGR) | ||||
| 				key = scan_code_to_key_altgr[ch]; | ||||
| 			else | ||||
| 				key = scan_code_to_key_normal[ch]; | ||||
| 		} | ||||
| 
 | ||||
| 		if ((s_led_states & I8042_KB_LED_NUM_LOCK)) | ||||
| 		{ | ||||
| 			switch (key) | ||||
| 			{ | ||||
| 				case Key::Numpad0:		key = Key::Insert;		break; | ||||
| 				case Key::Numpad1:		key = Key::End;			break; | ||||
| 				case Key::Numpad2:		key = Key::Down;		break; | ||||
| 				case Key::Numpad3:		key = Key::PageDown;	break; | ||||
| 				case Key::Numpad4:		key = Key::Left;		break; | ||||
| 				case Key::Numpad5:		key = Key::None;		break; | ||||
| 				case Key::Numpad6:		key = Key::Right;		break; | ||||
| 				case Key::Numpad7:		key = Key::Home;		break; | ||||
| 				case Key::Numpad8:		key = Key::Up;			break; | ||||
| 				case Key::Numpad9:		key = Key::PageUp;		break; | ||||
| 				case Key::NumpadSep:	key = Key::Delete;		break; | ||||
| 				default: break; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 
 | ||||
| #if KEYBOARD_SHOW_UNKNOWN | ||||
| 		if (key == Key::INVALID) | ||||
| 			kprintln("{} {}", ch, extended ? 'E' : ' '); | ||||
| #endif | ||||
| 
 | ||||
| 		s_keyboard_state[(int)key] = pressed; | ||||
| 
 | ||||
| 		bool update_leds = false; | ||||
| 		switch (key) | ||||
| 		{ | ||||
| 			case Key::ScrollLock: | ||||
| 				update_leds = pressed; | ||||
| 				if (update_leds) | ||||
| 					s_led_states ^= I8042_KB_LED_SCROLL_LOCK; | ||||
| 				break; | ||||
| 			case Key::NumLock: | ||||
| 				update_leds = pressed; | ||||
| 				if (update_leds) | ||||
| 					s_led_states ^= I8042_KB_LED_NUM_LOCK; | ||||
| 				break; | ||||
| 			case Key::CapsLock: | ||||
| 				update_leds = pressed; | ||||
| 				if (update_leds) | ||||
| 					s_led_states ^= I8042_KB_LED_CAPS_LOCK; | ||||
| 				break; | ||||
| 			default: | ||||
| 				break; | ||||
| 		} | ||||
| 
 | ||||
| 		if (update_leds) | ||||
| 		{ | ||||
| 			MUST(s_command_queue.push({ | ||||
| 				.target = TARGET_KEYBOARD, | ||||
| 				.command = I8042_KB_SET_LEDS, | ||||
| 				.data = s_led_states, | ||||
| 				.has_data = true, | ||||
| 			})); | ||||
| 		} | ||||
| 
 | ||||
| 		uint8_t modifiers = 0; | ||||
| 		if (s_keyboard_state[(int)Key::LeftShift] || s_keyboard_state[(int)Key::RightShift]) | ||||
| 			modifiers |= MOD_SHIFT; | ||||
| 		if (s_keyboard_state[(int)Key::LeftCtrl] || s_keyboard_state[(int)Key::RightCtrl]) | ||||
| 			modifiers |= MOD_CTRL; | ||||
| 		if (s_keyboard_state[(int)Key::LeftAlt]) | ||||
| 			modifiers |= MOD_ALT; | ||||
| 		if (s_keyboard_state[(int)Key::RightAlt]) | ||||
| 			modifiers |= MOD_ALTGR; | ||||
| 		if (s_led_states & I8042_KB_LED_CAPS_LOCK) | ||||
| 			modifiers |= MOD_CAPS; | ||||
| 		s_modifiers = modifiers; | ||||
| 
 | ||||
| 		if (key != Key::INVALID) | ||||
| 		{ | ||||
| 			auto error_or = s_key_event_queue.push({ .key = key, .modifiers = modifiers, .pressed = pressed }); | ||||
| 			if (error_or.is_error()) | ||||
| 				dwarnln("{}", error_or.error()); | ||||
| 		} | ||||
| 		s_keyboard_key_buffer_size -= index + 1; | ||||
| 		memmove(s_keyboard_key_buffer, s_keyboard_key_buffer + index, s_keyboard_key_buffer_size); | ||||
| 	} | ||||
| 
 | ||||
| 	static void keyboard_irq_handler() | ||||
| 	{ | ||||
| 		uint8_t raw = IO::inb(I8042_DATA_PORT); | ||||
| #if DEBUG_ALL_IRQ | ||||
| 		dprintln("k 0x{2H}", raw); | ||||
| #endif | ||||
| 		i8042_handle_byte(TARGET_KEYBOARD, raw); | ||||
| 	} | ||||
| 
 | ||||
| 	static void mouse_irq_handler() | ||||
| 	{ | ||||
| 		uint8_t raw = IO::inb(I8042_DATA_PORT); | ||||
| #if DEBUG_ALL_IRQ | ||||
| 		dprintln("m 0x{2H}", raw); | ||||
| #endif | ||||
| 		i8042_handle_byte(TARGET_MOUSE, raw); | ||||
| 	} | ||||
| 
 | ||||
| 	static void initialize_keyboard() | ||||
| 	{ | ||||
| 		// Register callback and IRQ
 | ||||
| 		IDT::register_irq_handler(KEYBOARD_IRQ, keyboard_irq_handler); | ||||
| 		InterruptController::get().enable_irq(KEYBOARD_IRQ); | ||||
| 		i8042_controller_command(I8042_ENABLE_FIRST_PORT); | ||||
| 
 | ||||
| 		MUST(s_command_queue.push({ | ||||
| 			.target = TARGET_KEYBOARD, | ||||
| 			.command = I8042_KB_RESET, | ||||
| 			.resp_cnt = 1, | ||||
| 		})); | ||||
| 
 | ||||
| 		// Set scan code set 2
 | ||||
| 		MUST(s_command_queue.push({ | ||||
| 			.target = TARGET_KEYBOARD, | ||||
| 			.command = I8042_KB_SET_SCAN_CODE_SET, | ||||
| 			.data = 0x02, | ||||
| 			.has_data = true, | ||||
| 		})); | ||||
| 
 | ||||
| 		// Turn LEDs off
 | ||||
| 		MUST(s_command_queue.push({ | ||||
| 			.target = TARGET_KEYBOARD, | ||||
| 			.command = I8042_KB_SET_LEDS, | ||||
| 			.data = s_led_states, | ||||
| 			.has_data = true, | ||||
| 		})); | ||||
| 	} | ||||
| 
 | ||||
| 	static void initialize_mouse() | ||||
| 	{ | ||||
| 		// Register callback and IRQ
 | ||||
| 		IDT::register_irq_handler(MOUSE_IRQ, mouse_irq_handler); | ||||
| 		InterruptController::get().enable_irq(MOUSE_IRQ); | ||||
| 		i8042_controller_command(I8042_ENABLE_SECOND_PORT); | ||||
| 
 | ||||
| 		MUST(s_command_queue.push({ | ||||
| 			.target = TARGET_MOUSE, | ||||
| 			.command = I8042_MOUSE_RESET, | ||||
| 			.resp_cnt = 2, | ||||
| 		})); | ||||
| 
 | ||||
| 		// Mouse should be disabled when sending commands
 | ||||
| 		MUST(s_command_queue.push({ | ||||
| 			.target = TARGET_MOUSE, | ||||
| 			.command = I8042_MOUSE_ENABLE, | ||||
| 		})); | ||||
| 	} | ||||
| 
 | ||||
| 	bool initialize() | ||||
| 	{ | ||||
| 		// https://wiki.osdev.org/%228042%22_PS/2_Controller
 | ||||
| 
 | ||||
| 		// Step 1: Initialize USB Controllers
 | ||||
| 		// TODO
 | ||||
| 
 | ||||
| 		// Stem 2: Determine if the PS/2 Controller Exists
 | ||||
| 		// TODO
 | ||||
| 
 | ||||
| 		// Step 3: Disable Devices
 | ||||
| 		i8042_controller_command(I8042_DISABLE_FIRST_PORT); | ||||
| 		i8042_controller_command(I8042_DISABLE_SECOND_PORT); | ||||
| 
 | ||||
| 		// Step 4: Flush The Ouput Buffer
 | ||||
| 		while ((IO::inb(I8042_STATUS_REGISTER) & I8042_STATUS_OUT_FULL) != 0) | ||||
| 			IO::inb(I8042_DATA_PORT); | ||||
| 
 | ||||
| 		// Step 5: Set the Controller Configuration Byte
 | ||||
| 		i8042_controller_command(I8042_READ_CONFIG); | ||||
| 		uint8_t config = wait_and_read(); | ||||
| 		config &= ~(I8042_CONFING_IRQ_FIRST | I8042_CONFING_IRQ_SECOND); | ||||
| 		i8042_controller_command(I8042_WRITE_CONFIG, config); | ||||
| 
 | ||||
| 
 | ||||
| 		// Step 6: Perform Controller Self Test
 | ||||
| 		i8042_controller_command(I8042_TEST_CONTROLLER); | ||||
| 		if (wait_and_read() != I8042_TEST_CONTROLLER_PASS) | ||||
| 		{ | ||||
| 			derrorln("PS/2 controller self test failed"); | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		// Step 7: Determine If There Are 2 Channels
 | ||||
| 		bool dual_channel = MOUSE_ENABLED ? config & I8042_CONFING_DUAL_CHANNEL : false; | ||||
| 		if (dual_channel) | ||||
| 		{ | ||||
| 			i8042_controller_command(I8042_ENABLE_SECOND_PORT); | ||||
| 			i8042_controller_command(I8042_READ_CONFIG); | ||||
| 			if (wait_and_read() & I8042_CONFING_DUAL_CHANNEL) | ||||
| 				dual_channel = false; | ||||
| 			else | ||||
| 				i8042_controller_command(I8042_DISABLE_SECOND_PORT); | ||||
| 		} | ||||
| 
 | ||||
| 		// Step 8: Perform Interface Tests
 | ||||
| 		i8042_controller_command(I8042_TEST_FIRST_PORT); | ||||
| 		if (wait_and_read() != I8042_TEST_FIRST_PORT_PASS) | ||||
| 		{ | ||||
| 			derrorln("PS/2 first port test failed"); | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		if (dual_channel) | ||||
| 		{ | ||||
| 			i8042_controller_command(I8042_TEST_SECOND_PORT); | ||||
| 			if (wait_and_read() != I8042_TEST_SECOND_PORT_PASS) | ||||
| 			{ | ||||
| 				dwarnln("PS/2 second port test failed. Mouse will be disabled"); | ||||
| 				dual_channel = false; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// Step 9: Enable Devices
 | ||||
| 		config |= I8042_CONFING_IRQ_FIRST; | ||||
| 		if (dual_channel) | ||||
| 			config |= I8042_CONFING_IRQ_SECOND; | ||||
| 		i8042_controller_command(I8042_WRITE_CONFIG, config); | ||||
| 
 | ||||
| 		// Step 10: Reset Devices
 | ||||
| 		initialize_keyboard(); | ||||
| 		if (dual_channel) | ||||
| 			initialize_mouse(); | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	void register_key_event_callback(const BAN::Function<void(KeyEvent)>& callback) | ||||
| 	{ | ||||
| 		s_key_event_callback = callback; | ||||
| 	} | ||||
| 
 | ||||
| 	void register_mouse_button_event_callback(const BAN::Function<void(MouseButtonEvent)>& callback) | ||||
| 	{ | ||||
| 		s_mouse_button_event_callback = callback; | ||||
| 	} | ||||
| 
 | ||||
| 	void register_mouse_move_event_callback(const BAN::Function<void(MouseMoveEvent)>& callback) | ||||
| 	{ | ||||
| 		s_mouse_move_event_callback = callback; | ||||
| 	} | ||||
| 
 | ||||
| 	const char* key_event_to_utf8(KeyEvent event) | ||||
| 	{ | ||||
| 		bool shift = event.modifiers & MOD_SHIFT; | ||||
| 		bool caps = event.modifiers & MOD_CAPS; | ||||
| 		if (shift ^ caps) | ||||
| 			return s_key_to_utf8_upper[(int)event.key]; | ||||
| 		return s_key_to_utf8_lower[(int)event.key]; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,334 @@ | |||
| #include <BAN/ScopeGuard.h> | ||||
| #include <kernel/ACPI.h> | ||||
| #include <kernel/IDT.h> | ||||
| #include <kernel/Input/PS2Controller.h> | ||||
| #include <kernel/Input/PS2Keyboard.h> | ||||
| #include <kernel/InterruptController.h> | ||||
| #include <kernel/IO.h> | ||||
| 
 | ||||
| namespace Kernel::Input | ||||
| { | ||||
| 
 | ||||
| 	namespace PS2 | ||||
| 	{ | ||||
| 
 | ||||
| 		enum IOPort : uint8_t | ||||
| 		{ | ||||
| 			DATA = 0x60, | ||||
| 			STATUS = 0x64, | ||||
| 			COMMAND = 0x64, | ||||
| 		}; | ||||
| 
 | ||||
| 		enum Status : uint8_t | ||||
| 		{ | ||||
| 			OUTPUT_FULL = (1 << 0), | ||||
| 			INPUT_FULL = (1 << 1), | ||||
| 			SYSTEM = (1 << 2), | ||||
| 			DEVICE_OR_CONTROLLER = (1 << 3), | ||||
| 			TIMEOUT_ERROR = (1 << 6), | ||||
| 			PARITY_ERROR = (1 << 7), | ||||
| 		}; | ||||
| 
 | ||||
| 		enum Config : uint8_t | ||||
| 		{ | ||||
| 			INTERRUPT_FIRST_PORT = (1 << 0), | ||||
| 			INTERRUPT_SECOND_PORT = (1 << 1), | ||||
| 			SYSTEM_FLAG = (1 << 2), | ||||
| 			ZERO1 = (1 << 3), | ||||
| 			CLOCK_FIRST_PORT = (1 << 4), | ||||
| 			CLOCK_SECOND_PORT = (1 << 5), | ||||
| 			TRANSLATION_FIRST_PORT = (1 << 6), | ||||
| 			ZERO2 = (1 << 7), | ||||
| 		}; | ||||
| 
 | ||||
| 		enum Command : uint8_t | ||||
| 		{ | ||||
| 			READ_CONFIG = 0x20, | ||||
| 			WRITE_CONFIG = 0x60, | ||||
| 			DISABLE_SECOND_PORT = 0xA7, | ||||
| 			ENABLE_SECOND_PORT = 0xA8, | ||||
| 			TEST_SECOND_PORT = 0xA9, | ||||
| 			TEST_CONTROLLER = 0xAA, | ||||
| 			TEST_FIRST_PORT = 0xAB, | ||||
| 			DISABLE_FIRST_PORT = 0xAD, | ||||
| 			ENABLE_FIRST_PORT = 0xAE, | ||||
| 			WRITE_TO_SECOND_PORT = 0xD4, | ||||
| 		}; | ||||
| 
 | ||||
| 		enum Response | ||||
| 		{ | ||||
| 			TEST_FIRST_PORT_PASS = 0x00, | ||||
| 			TEST_SECOND_PORT_PASS = 0x00, | ||||
| 			TEST_CONTROLLER_PASS = 0x55, | ||||
| 			SELF_TEST_PASS = 0xAA, | ||||
| 			ACK = 0xFA, | ||||
| 		}; | ||||
| 
 | ||||
| 		enum DeviceCommand | ||||
| 		{ | ||||
| 			ENABLE_SCANNING = 0xF4, | ||||
| 			DISABLE_SCANNING = 0xF5, | ||||
| 			IDENTIFY = 0xF2, | ||||
| 			RESET = 0xFF, | ||||
| 		}; | ||||
| 
 | ||||
| 		enum IRQ | ||||
| 		{ | ||||
| 			DEVICE0 = 1, | ||||
| 			DEVICE1 = 12, | ||||
| 		}; | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	static constexpr uint64_t s_device_timeout_ms = 100; | ||||
| 
 | ||||
| 	static void controller_send_command(PS2::Command command) | ||||
| 	{ | ||||
| 		IO::outb(PS2::IOPort::COMMAND, command); | ||||
| 	} | ||||
| 
 | ||||
| 	static void controller_send_command(PS2::Command command, uint8_t data) | ||||
| 	{ | ||||
| 		IO::outb(PS2::IOPort::COMMAND, command); | ||||
| 		while (IO::inb(PS2::IOPort::STATUS) & PS2::Status::INPUT_FULL) | ||||
| 			continue; | ||||
| 		IO::outb(PS2::IOPort::DATA, data); | ||||
| 	} | ||||
| 
 | ||||
| 	static uint8_t wait_and_read() | ||||
| 	{ | ||||
| 		while (!(IO::inb(PS2::IOPort::STATUS) & PS2::Status::OUTPUT_FULL)) | ||||
| 			continue; | ||||
| 		return IO::inb(PS2::IOPort::DATA); | ||||
| 	} | ||||
| 
 | ||||
| 	static BAN::ErrorOr<void> device_send_byte(uint8_t device, uint8_t byte) | ||||
| 	{ | ||||
| 		if (device == 1) | ||||
| 			IO::outb(PS2::IOPort::COMMAND, PS2::Command::WRITE_TO_SECOND_PORT); | ||||
| 		uint64_t timeout = PIT::ms_since_boot() + s_device_timeout_ms; | ||||
| 		while (PIT::ms_since_boot() < timeout) | ||||
| 		{ | ||||
| 			if (!(IO::inb(PS2::IOPort::STATUS) & PS2::Status::INPUT_FULL)) | ||||
| 			{ | ||||
| 				IO::outb(PS2::IOPort::DATA, byte); | ||||
| 				return {}; | ||||
| 			} | ||||
| 		} | ||||
| 		return BAN::Error::from_c_string("PS/2 device timeout"); | ||||
| 	} | ||||
| 
 | ||||
| 	static BAN::ErrorOr<uint8_t> device_read_byte() | ||||
| 	{ | ||||
| 		uint64_t timeout = PIT::ms_since_boot() + s_device_timeout_ms; | ||||
| 		while (PIT::ms_since_boot() < timeout) | ||||
| 			if (IO::inb(PS2::IOPort::STATUS) & PS2::Status::OUTPUT_FULL) | ||||
| 				return IO::inb(PS2::IOPort::DATA); | ||||
| 		return BAN::Error::from_c_string("PS/2 device timeout"); | ||||
| 	} | ||||
| 
 | ||||
| 	static BAN::ErrorOr<void> device_wait_ack() | ||||
| 	{ | ||||
| 		while (TRY(device_read_byte()) != PS2::Response::ACK) | ||||
| 			continue;; | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	void PS2Controller::device0_irq() | ||||
| 	{ | ||||
| 		auto& controller = PS2Controller::get(); | ||||
| 		ASSERT(controller.m_devices[0] != nullptr); | ||||
| 		controller.m_devices[0]->on_byte(IO::inb(PS2::IOPort::DATA)); | ||||
| 	} | ||||
| 
 | ||||
| 	void PS2Controller::device1_irq() | ||||
| 	{ | ||||
| 		auto& controller = PS2Controller::get(); | ||||
| 		ASSERT(controller.m_devices[1] != nullptr); | ||||
| 		controller.m_devices[1]->on_byte(IO::inb(PS2::IOPort::DATA)); | ||||
| 	} | ||||
| 
 | ||||
| 	static PS2Controller* s_instance = nullptr; | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> PS2Controller::initialize() | ||||
| 	{ | ||||
| 		ASSERT(s_instance == nullptr); | ||||
| 		s_instance = new PS2Controller; | ||||
| 		if (s_instance == nullptr) | ||||
| 			return BAN::Error::from_errno(ENOMEM); | ||||
| 		BAN::ScopeGuard guard([] { delete s_instance; }); | ||||
| 		TRY(s_instance->initialize_impl()); | ||||
| 		guard.disable(); | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	PS2Controller& PS2Controller::get() | ||||
| 	{ | ||||
| 		ASSERT(s_instance != nullptr); | ||||
| 		return *s_instance; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> PS2Controller::initialize_impl() | ||||
| 	{ | ||||
| 		// Step 1: Initialise USB Controllers
 | ||||
| 		// FIXME
 | ||||
| 
 | ||||
| 		// Step 2: Determine if the PS/2 Controller Exists
 | ||||
| 		if (false) | ||||
| 		{ | ||||
| 			const ACPI::FADT* fadt = (const ACPI::FADT*)TRY(ACPI::get().get_header("FACP")); | ||||
| 			bool ps2_exists = fadt->iapc_boot_arch & (1 << 1); | ||||
| 			ACPI::get().unmap_header(fadt); | ||||
| 
 | ||||
| 			if (!ps2_exists) | ||||
| 				return BAN::Error::from_c_string("PS2 Controller does not exist"); | ||||
| 		} | ||||
| 
 | ||||
| 		// Step 3: Disable Devices
 | ||||
| 		controller_send_command(PS2::Command::DISABLE_FIRST_PORT); | ||||
| 		controller_send_command(PS2::Command::DISABLE_SECOND_PORT); | ||||
| 
 | ||||
| 		// Step 4: Flush The Output Buffer
 | ||||
| 		IO::inb(PS2::IOPort::DATA); | ||||
| 		 | ||||
| 		// Step 5: Set the Controller Configuration Byte
 | ||||
| 		controller_send_command(PS2::Command::READ_CONFIG); | ||||
| 		uint8_t config = wait_and_read(); | ||||
| 		config &= ~PS2::Config::INTERRUPT_FIRST_PORT; | ||||
| 		config &= ~PS2::Config::INTERRUPT_SECOND_PORT; | ||||
| 		config &= ~PS2::Config::TRANSLATION_FIRST_PORT; | ||||
| 		controller_send_command(PS2::Command::WRITE_CONFIG, config); | ||||
| 
 | ||||
| 		// Step 6: Perform Controller Self Test
 | ||||
| 		controller_send_command(PS2::Command::TEST_CONTROLLER); | ||||
| 		if (wait_and_read() != PS2::Response::TEST_CONTROLLER_PASS) | ||||
| 			return BAN::Error::from_c_string("PS/2 Controller self test failed"); | ||||
| 		// NOTE: self test might reset the device so we set the config byte again
 | ||||
| 		controller_send_command(PS2::Command::WRITE_CONFIG, config); | ||||
| 
 | ||||
| 		// Step 7: Determine If There Are 2 Channels
 | ||||
| 		bool valid_ports[2] { true, false }; | ||||
| 		if (config & PS2::Config::CLOCK_SECOND_PORT) | ||||
| 		{ | ||||
| 			controller_send_command(PS2::Command::ENABLE_SECOND_PORT); | ||||
| 			controller_send_command(PS2::Command::READ_CONFIG); | ||||
| 			if (!(wait_and_read() & PS2::Config::CLOCK_SECOND_PORT)) | ||||
| 				valid_ports[1] = true; | ||||
| 			controller_send_command(PS2::Command::DISABLE_SECOND_PORT); | ||||
| 		} | ||||
| 
 | ||||
| 		// Step 8: Perform Interface Tests
 | ||||
| 		controller_send_command(PS2::Command::TEST_FIRST_PORT); | ||||
| 		if (wait_and_read() != PS2::Response::TEST_FIRST_PORT_PASS) | ||||
| 			valid_ports[0] = false; | ||||
| 		if (valid_ports[1]) | ||||
| 		{ | ||||
| 			controller_send_command(PS2::Command::TEST_SECOND_PORT); | ||||
| 			if (wait_and_read() != PS2::Response::TEST_SECOND_PORT_PASS) | ||||
| 				valid_ports[1] = false; | ||||
| 		} | ||||
| 		if (!valid_ports[0] && !valid_ports[1]) | ||||
| 			return BAN::Error::from_c_string("No ports available on Controller"); | ||||
| 		 | ||||
| 		// Step 9: Enable Devices (and disable scanning)
 | ||||
| 		for (uint8_t device = 0; device < 2; device++) | ||||
| 		{ | ||||
| 			if (!valid_ports[device]) | ||||
| 				continue; | ||||
| 			controller_send_command(device == 0 ? PS2::Command::ENABLE_FIRST_PORT : PS2::Command::ENABLE_SECOND_PORT); | ||||
| 			if (set_scanning(device, false).is_error()) | ||||
| 				valid_ports[device] = false; | ||||
| 		} | ||||
| 
 | ||||
| 		// Step 10: Reset Devices
 | ||||
| 		for (uint8_t device = 0; device < 2; device++) | ||||
| 		{ | ||||
| 			if (!valid_ports[device]) | ||||
| 				continue; | ||||
| 			if (reset_device(device).is_error()) | ||||
| 				valid_ports[device] = false; | ||||
| 			if (set_scanning(device, false).is_error()) | ||||
| 				valid_ports[device] = false; | ||||
| 		} | ||||
| 
 | ||||
| 		// 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()) | ||||
| 				dprintln("{}", res.error()); | ||||
| 		} | ||||
| 
 | ||||
| 		if (m_devices[0]) | ||||
| 		{ | ||||
| 			IDT::register_irq_handler(PS2::IRQ::DEVICE0, device0_irq); | ||||
| 			InterruptController::get().enable_irq(PS2::IRQ::DEVICE0); | ||||
| 			config |= PS2::Config::INTERRUPT_FIRST_PORT; | ||||
| 			DeviceManager::get().add_device(m_devices[0]); | ||||
| 		} | ||||
| 		if (m_devices[1]) | ||||
| 		{ | ||||
| 			IDT::register_irq_handler(PS2::IRQ::DEVICE1, device1_irq); | ||||
| 			InterruptController::get().enable_irq(PS2::IRQ::DEVICE1); | ||||
| 			config |= PS2::Config::INTERRUPT_SECOND_PORT; | ||||
| 			DeviceManager::get().add_device(m_devices[1]); | ||||
| 		} | ||||
| 
 | ||||
| 		controller_send_command(PS2::Command::WRITE_CONFIG, config); | ||||
| 			 | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> PS2Controller::initialize_device(uint8_t device) | ||||
| 	{ | ||||
| 		TRY(device_send_byte(device, PS2::DeviceCommand::IDENTIFY)); | ||||
| 		TRY(device_wait_ack()); | ||||
| 
 | ||||
| 		uint8_t bytes[2] {}; | ||||
| 		uint8_t index = 0; | ||||
| 		for (uint8_t i = 0; i < 2; i++) | ||||
| 		{ | ||||
| 			auto res = device_read_byte(); | ||||
| 			if (res.is_error()) | ||||
| 				break; | ||||
| 			bytes[index++] = res.value(); | ||||
| 		} | ||||
| 
 | ||||
| 		// Standard PS/2 Mouse
 | ||||
| 		if (index == 1 && (bytes[0] == 0x00)) | ||||
| 			return BAN::Error::from_c_string("PS/2 mouse not supported"); | ||||
| 		 | ||||
| 		// MF2 Keyboard
 | ||||
| 		if (index == 2 && (bytes[0] == 0xAB && bytes[1] == 0x83)) | ||||
| 			m_devices[device] = TRY(PS2Keyboard::create(*this)); | ||||
| 
 | ||||
| 		if (m_devices[device]) | ||||
| 			return {}; | ||||
| 		return BAN::Error::from_format("Unhandled PS/2 device {}{} ({} bytes)", bytes[0], bytes[1], index); | ||||
| 	} | ||||
| 
 | ||||
| 	void PS2Controller::send_byte(const PS2Device* device, uint8_t byte) | ||||
| 	{ | ||||
| 		ASSERT(device != nullptr && (device == m_devices[0] || device == m_devices[1])); | ||||
| 		uint8_t device_index = (device == m_devices[0]) ? 0 : 1; | ||||
| 		MUST(device_send_byte(device_index, byte)); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> PS2Controller::reset_device(uint8_t device) | ||||
| 	{ | ||||
| 		TRY(device_send_byte(device, PS2::DeviceCommand::RESET)); | ||||
| 		TRY(device_wait_ack()); | ||||
| 		if (TRY(device_read_byte()) != PS2::Response::SELF_TEST_PASS) | ||||
| 			return BAN::Error::from_c_string("Device reset failed"); | ||||
| 		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_wait_ack()); | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,244 @@ | |||
| #include <BAN/ScopeGuard.h> | ||||
| #include <kernel/CriticalScope.h> | ||||
| #include <kernel/Input/PS2Keyboard.h> | ||||
| 
 | ||||
| #define SET_MASK(byte, mask, on_off) ((on_off) ? ((byte) | (mask)) : ((byte) & ~(mask))) | ||||
| #define TOGGLE_MASK(byte, mask) ((byte) ^ (mask)) | ||||
| 
 | ||||
| namespace Kernel::Input | ||||
| { | ||||
| 
 | ||||
| 	namespace PS2 | ||||
| 	{ | ||||
| 
 | ||||
| 		enum Response | ||||
| 		{ | ||||
| 			KEY_ERROR_OR_BUFFER_OVERRUN1 = 0x00, | ||||
| 			SELF_TEST_PASSED = 0xAA, | ||||
| 			ECHO_RESPONSE = 0xEE, | ||||
| 			ACK = 0xFA, | ||||
| 			RESEND = 0xFE, | ||||
| 			KEY_ERROR_OR_BUFFER_OVERRUN2 = 0xFF, | ||||
| 		}; | ||||
| 
 | ||||
| 		enum Scancode | ||||
| 		{ | ||||
| 			SET_SCANCODE_SET1 = 1, | ||||
| 			SET_SCANCODE_SET2 = 2, | ||||
| 			SET_SCANCODE_SET3 = 3, | ||||
| 		}; | ||||
| 
 | ||||
| 		enum Leds | ||||
| 		{ | ||||
| 			SCROLL_LOCK	= (1 << 0), | ||||
| 			NUM_LOCK	= (1 << 1), | ||||
| 			CAPS_LOCK	= (1 << 2), | ||||
| 		}; | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<PS2Keyboard*> PS2Keyboard::create(PS2Controller& controller) | ||||
| 	{ | ||||
| 		PS2Keyboard* keyboard = new PS2Keyboard(controller); | ||||
| 		if (keyboard == nullptr) | ||||
| 			return BAN::Error::from_errno(ENOMEM); | ||||
| 		BAN::ScopeGuard guard([keyboard] { delete keyboard; }); | ||||
| 		TRY(keyboard->initialize()); | ||||
| 		guard.disable(); | ||||
| 		return keyboard; | ||||
| 	} | ||||
| 
 | ||||
| 	void PS2Keyboard::on_byte(uint8_t byte) | ||||
| 	{ | ||||
| 		// NOTE: This implementation does not allow using commands
 | ||||
| 		//       that respond with more bytes than ACK
 | ||||
| 		switch (m_state) | ||||
| 		{ | ||||
| 			case State::WaitingAck: | ||||
| 			{ | ||||
| 				switch (byte) | ||||
| 				{ | ||||
| 					case PS2::Response::ACK: | ||||
| 						m_command_queue.pop(); | ||||
| 						m_state = State::Normal; | ||||
| 						break; | ||||
| 					case PS2::Response::RESEND: | ||||
| 						m_state = State::Normal; | ||||
| 						break; | ||||
| 					case PS2::Response::KEY_ERROR_OR_BUFFER_OVERRUN1: | ||||
| 					case PS2::Response::KEY_ERROR_OR_BUFFER_OVERRUN2: | ||||
| 						dwarnln("Key detection error or internal buffer overrun"); | ||||
| 						break; | ||||
| 					default: | ||||
| 						dwarnln("Unhandeled byte {2H}", byte); | ||||
| 						break; | ||||
| 				} | ||||
| 				break; | ||||
| 			} | ||||
| 			case State::Normal: | ||||
| 			{ | ||||
| 				m_byte_buffer[m_byte_index++] = byte; | ||||
| 				if (byte != 0xE0 && byte != 0xF0) | ||||
| 					buffer_has_key(); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> PS2Keyboard::initialize() | ||||
| 	{ | ||||
| 		append_command_queue(Command::SET_LEDS, 0x00); | ||||
| 		append_command_queue(Command::SCANCODE, PS2::Scancode::SET_SCANCODE_SET2); | ||||
| 		append_command_queue(Command::ENABLE_SCANNING); | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	void PS2Keyboard::update() | ||||
| 	{ | ||||
| 		if (m_state == State::WaitingAck) | ||||
| 			return; | ||||
| 		if (m_command_queue.empty()) | ||||
| 			return; | ||||
| 		m_state = State::WaitingAck; | ||||
| 		m_controller.send_byte(this, m_command_queue.front()); | ||||
| 	} | ||||
| 
 | ||||
| 	void PS2Keyboard::append_command_queue(uint8_t byte) | ||||
| 	{ | ||||
| 		if (m_command_queue.full()) | ||||
| 		{ | ||||
| 			dwarnln("PS/2 command queue full"); | ||||
| 			return; | ||||
| 		} | ||||
| 		m_command_queue.push(byte); | ||||
| 	} | ||||
| 	 | ||||
| 	void PS2Keyboard::append_command_queue(uint8_t byte1, uint8_t byte2) | ||||
| 	{ | ||||
| 		if (m_command_queue.size() + 2 > m_command_queue.capacity()) | ||||
| 		{ | ||||
| 			dwarnln("PS/2 command queue full"); | ||||
| 			return; | ||||
| 		} | ||||
| 		m_command_queue.push(byte1); | ||||
| 		m_command_queue.push(byte2); | ||||
| 	} | ||||
| 
 | ||||
| 	void PS2Keyboard::buffer_has_key() | ||||
| 	{ | ||||
| 		uint32_t scancode = 0; | ||||
| 		bool extended = false; | ||||
| 		bool released = false; | ||||
| 
 | ||||
| 		for (uint8_t i = 0; i < m_byte_index; i++) | ||||
| 		{ | ||||
| 			if (m_byte_buffer[i] == 0xE0) | ||||
| 				extended = true; | ||||
| 			else if (m_byte_buffer[i] == 0xF0) | ||||
| 				released = true; | ||||
| 			else | ||||
| 				scancode = (scancode << 8) | m_byte_buffer[i]; | ||||
| 		} | ||||
| 
 | ||||
| 		if (extended) | ||||
| 			scancode |= 0x80000000; | ||||
| 
 | ||||
| 		m_byte_index = 0; | ||||
| 
 | ||||
| 		Key key = m_keymap.key_for_scancode_and_modifiers(scancode, m_modifiers); | ||||
| 
 | ||||
| 		if (key == Key::None) | ||||
| 			return; | ||||
| 
 | ||||
| 		if (key == Input::Key::Invalid) | ||||
| 		{ | ||||
| 			dprintln("unknown key for scancode {2H} {}", scancode & 0x7FFFFFFF, extended ? 'E' : ' '); | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		uint8_t modifier_mask = 0; | ||||
| 		uint8_t toggle_mask = 0; | ||||
| 		switch (key) | ||||
| 		{ | ||||
| 			case Input::Key::LeftShift: | ||||
| 			case Input::Key::RightShift: | ||||
| 				modifier_mask = (uint8_t)Input::KeyEvent::Modifier::Shift; | ||||
| 				break; | ||||
| 			case Input::Key::LeftCtrl: | ||||
| 			case Input::Key::RightCtrl: | ||||
| 				modifier_mask = (uint8_t)Input::KeyEvent::Modifier::Ctrl; | ||||
| 				break; | ||||
| 			case Input::Key::Alt: | ||||
| 				modifier_mask = (uint8_t)Input::KeyEvent::Modifier::Alt; | ||||
| 				break; | ||||
| 			case Input::Key::AltGr: | ||||
| 				modifier_mask = (uint8_t)Input::KeyEvent::Modifier::AltGr; | ||||
| 				break;; | ||||
| 			case Input::Key::ScrollLock: | ||||
| 				toggle_mask = (uint8_t)Input::KeyEvent::Modifier::ScrollLock; | ||||
| 				break; | ||||
| 			case Input::Key::NumLock: | ||||
| 				toggle_mask = (uint8_t)Input::KeyEvent::Modifier::NumLock; | ||||
| 				break; | ||||
| 			case Input::Key::CapsLock: | ||||
| 				toggle_mask = (uint8_t)Input::KeyEvent::Modifier::CapsLock; | ||||
| 				break; | ||||
| 			default: | ||||
| 				break; | ||||
| 		} | ||||
| 
 | ||||
| 		if (modifier_mask) | ||||
| 		{ | ||||
| 			if (released) | ||||
| 				m_modifiers &= ~modifier_mask; | ||||
| 			else | ||||
| 				m_modifiers |= modifier_mask; | ||||
| 		} | ||||
| 
 | ||||
| 		if (toggle_mask && !released) | ||||
| 		{ | ||||
| 			m_modifiers ^= toggle_mask; | ||||
| 			update_leds(); | ||||
| 		} | ||||
| 
 | ||||
| 		Input::KeyEvent event; | ||||
| 		event.modifier = m_modifiers | (released ? (uint8_t)Input::KeyEvent::Modifier::Released : 0); | ||||
| 		event.key = key; | ||||
| 
 | ||||
| 		if (m_event_queue.full()) | ||||
| 		{ | ||||
| 			dwarnln("PS/2 event queue full"); | ||||
| 			m_event_queue.pop(); | ||||
| 		} | ||||
| 		m_event_queue.push(event); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	void PS2Keyboard::update_leds() | ||||
| 	{ | ||||
| 		uint8_t new_leds = 0; | ||||
| 		if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::ScrollLock) | ||||
| 			new_leds |= PS2::Leds::SCROLL_LOCK; | ||||
| 		if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::NumLock) | ||||
| 			new_leds |= PS2::Leds::NUM_LOCK; | ||||
| 		if (m_modifiers & (uint8_t)Input::KeyEvent::Modifier::CapsLock) | ||||
| 			new_leds |= PS2::Leds::CAPS_LOCK; | ||||
| 		append_command_queue(Command::SET_LEDS, new_leds); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> PS2Keyboard::read(BAN::Span<uint8_t> output) | ||||
| 	{ | ||||
| 		if (output.size() < sizeof(Input::KeyEvent)) | ||||
| 			return BAN::Error::from_c_string("Too small buffer for KeyEvent"); | ||||
| 
 | ||||
| 		while (m_event_queue.empty()) | ||||
| 			PIT::sleep(1); | ||||
| 
 | ||||
| 		CriticalScope _; | ||||
| 		*(Input::KeyEvent*)output.data() = m_event_queue.front(); | ||||
| 		m_event_queue.pop(); | ||||
| 
 | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,360 @@ | |||
| #include <kernel/Input/PS2Keymap.h> | ||||
| 
 | ||||
| namespace Kernel::Input | ||||
| { | ||||
| 
 | ||||
| 	PS2Keymap::PS2Keymap() | ||||
| 	{ | ||||
| 		MUST(m_normal_keymap.resize(0xFF, Key::Invalid)); | ||||
| 		m_normal_keymap[0x01] = Key::F9; | ||||
| 		m_normal_keymap[0x03] = Key::F5; | ||||
| 		m_normal_keymap[0x04] = Key::F3; | ||||
| 		m_normal_keymap[0x05] = Key::F1; | ||||
| 		m_normal_keymap[0x06] = Key::F2; | ||||
| 		m_normal_keymap[0x07] = Key::F11; | ||||
| 		m_normal_keymap[0x09] = Key::F10; | ||||
| 		m_normal_keymap[0x0A] = Key::F8; | ||||
| 		m_normal_keymap[0x0B] = Key::F6; | ||||
| 		m_normal_keymap[0x0C] = Key::F4; | ||||
| 		m_normal_keymap[0x0D] = Key::Tab; | ||||
| 		m_normal_keymap[0x0E] = Key::Section; | ||||
| 		m_normal_keymap[0x11] = Key::Alt; | ||||
| 		m_normal_keymap[0x12] = Key::LeftShift; | ||||
| 		m_normal_keymap[0x14] = Key::LeftCtrl; | ||||
| 		m_normal_keymap[0x15] = Key::Q; | ||||
| 		m_normal_keymap[0x16] = Key::_1; | ||||
| 		m_normal_keymap[0x1A] = Key::Z; | ||||
| 		m_normal_keymap[0x1B] = Key::S; | ||||
| 		m_normal_keymap[0x1C] = Key::A; | ||||
| 		m_normal_keymap[0x1D] = Key::W; | ||||
| 		m_normal_keymap[0x1E] = Key::_2; | ||||
| 		m_normal_keymap[0x21] = Key::C; | ||||
| 		m_normal_keymap[0x22] = Key::X; | ||||
| 		m_normal_keymap[0x23] = Key::D; | ||||
| 		m_normal_keymap[0x24] = Key::E; | ||||
| 		m_normal_keymap[0x25] = Key::_4; | ||||
| 		m_normal_keymap[0x26] = Key::_3; | ||||
| 		m_normal_keymap[0x29] = Key::Space; | ||||
| 		m_normal_keymap[0x2A] = Key::V; | ||||
| 		m_normal_keymap[0x2B] = Key::F; | ||||
| 		m_normal_keymap[0x2C] = Key::T; | ||||
| 		m_normal_keymap[0x2D] = Key::R; | ||||
| 		m_normal_keymap[0x2E] = Key::_5; | ||||
| 		m_normal_keymap[0x31] = Key::N; | ||||
| 		m_normal_keymap[0x32] = Key::B; | ||||
| 		m_normal_keymap[0x33] = Key::H; | ||||
| 		m_normal_keymap[0x34] = Key::G; | ||||
| 		m_normal_keymap[0x35] = Key::Y; | ||||
| 		m_normal_keymap[0x36] = Key::_6; | ||||
| 		m_normal_keymap[0x3A] = Key::M; | ||||
| 		m_normal_keymap[0x3B] = Key::J; | ||||
| 		m_normal_keymap[0x3C] = Key::U; | ||||
| 		m_normal_keymap[0x3D] = Key::_7; | ||||
| 		m_normal_keymap[0x3E] = Key::_8; | ||||
| 		m_normal_keymap[0x41] = Key::Comma; | ||||
| 		m_normal_keymap[0x42] = Key::K; | ||||
| 		m_normal_keymap[0x43] = Key::I; | ||||
| 		m_normal_keymap[0x44] = Key::O; | ||||
| 		m_normal_keymap[0x45] = Key::_0; | ||||
| 		m_normal_keymap[0x46] = Key::_9; | ||||
| 		m_normal_keymap[0x49] = Key::Period; | ||||
| 		m_normal_keymap[0x4A] = Key::Hyphen; | ||||
| 		m_normal_keymap[0x4B] = Key::L; | ||||
| 		m_normal_keymap[0x4C] = Key::O_Umlaut; | ||||
| 		m_normal_keymap[0x4D] = Key::P; | ||||
| 		m_normal_keymap[0x4E] = Key::Plus; | ||||
| 		m_normal_keymap[0x52] = Key::A_Umlaut; | ||||
| 		m_normal_keymap[0x54] = Key::A_Ring; | ||||
| 		m_normal_keymap[0x55] = Key::Acute; | ||||
| 		m_normal_keymap[0x58] = Key::CapsLock; | ||||
| 		m_normal_keymap[0x59] = Key::RightShift; | ||||
| 		m_normal_keymap[0x59] = Key::RightShift; | ||||
| 		m_normal_keymap[0x5A] = Key::Enter; | ||||
| 		m_normal_keymap[0x5B] = Key::TwoDots; | ||||
| 		m_normal_keymap[0x5D] = Key::SingleQuote; | ||||
| 		m_normal_keymap[0x61] = Key::LessThan; | ||||
| 		m_normal_keymap[0x66] = Key::Backspace; | ||||
| 		m_normal_keymap[0x69] = Key::Numpad1; | ||||
| 		m_normal_keymap[0x6B] = Key::Numpad4; | ||||
| 		m_normal_keymap[0x6C] = Key::Numpad7; | ||||
| 		m_normal_keymap[0x70] = Key::Numpad0; | ||||
| 		m_normal_keymap[0x71] = Key::NumpadDecimal; | ||||
| 		m_normal_keymap[0x72] = Key::Numpad2; | ||||
| 		m_normal_keymap[0x73] = Key::Numpad5; | ||||
| 		m_normal_keymap[0x74] = Key::Numpad6; | ||||
| 		m_normal_keymap[0x75] = Key::Numpad8; | ||||
| 		m_normal_keymap[0x76] = Key::Escape; | ||||
| 		m_normal_keymap[0x77] = Key::NumLock; | ||||
| 		m_normal_keymap[0x78] = Key::F11; | ||||
| 		m_normal_keymap[0x79] = Key::NumpadPlus; | ||||
| 		m_normal_keymap[0x7A] = Key::Numpad3; | ||||
| 		m_normal_keymap[0x7B] = Key::NumpadMinus; | ||||
| 		m_normal_keymap[0x7C] = Key::NumpadMultiply; | ||||
| 		m_normal_keymap[0x7D] = Key::Numpad9; | ||||
| 		m_normal_keymap[0x83] = Key::F7; | ||||
| 
 | ||||
| 		MUST(m_shift_keymap.resize(0xFF, Key::Invalid)); | ||||
| 		m_shift_keymap[0x01] = Key::F9; | ||||
| 		m_shift_keymap[0x03] = Key::F5; | ||||
| 		m_shift_keymap[0x04] = Key::F3; | ||||
| 		m_shift_keymap[0x05] = Key::F1; | ||||
| 		m_shift_keymap[0x06] = Key::F2; | ||||
| 		m_shift_keymap[0x07] = Key::F11; | ||||
| 		m_shift_keymap[0x09] = Key::F10; | ||||
| 		m_shift_keymap[0x0A] = Key::F8; | ||||
| 		m_shift_keymap[0x0B] = Key::F6; | ||||
| 		m_shift_keymap[0x0C] = Key::F4; | ||||
| 		m_shift_keymap[0x0D] = Key::Tab; | ||||
| 		m_shift_keymap[0x0E] = Key::Half; | ||||
| 		m_shift_keymap[0x11] = Key::Alt; | ||||
| 		m_shift_keymap[0x12] = Key::LeftShift; | ||||
| 		m_shift_keymap[0x14] = Key::LeftCtrl; | ||||
| 		m_shift_keymap[0x15] = Key::Q; | ||||
| 		m_shift_keymap[0x16] = Key::ExclamationMark; | ||||
| 		m_shift_keymap[0x1A] = Key::Z; | ||||
| 		m_shift_keymap[0x1B] = Key::S; | ||||
| 		m_shift_keymap[0x1C] = Key::A; | ||||
| 		m_shift_keymap[0x1D] = Key::W; | ||||
| 		m_shift_keymap[0x1E] = Key::DoubleQuote; | ||||
| 		m_shift_keymap[0x21] = Key::C; | ||||
| 		m_shift_keymap[0x22] = Key::X; | ||||
| 		m_shift_keymap[0x23] = Key::D; | ||||
| 		m_shift_keymap[0x24] = Key::E; | ||||
| 		m_shift_keymap[0x25] = Key::Currency; | ||||
| 		m_shift_keymap[0x26] = Key::Hashtag; | ||||
| 		m_shift_keymap[0x29] = Key::Space; | ||||
| 		m_shift_keymap[0x2A] = Key::V; | ||||
| 		m_shift_keymap[0x2B] = Key::F; | ||||
| 		m_shift_keymap[0x2C] = Key::T; | ||||
| 		m_shift_keymap[0x2D] = Key::R; | ||||
| 		m_shift_keymap[0x2E] = Key::Percent; | ||||
| 		m_shift_keymap[0x31] = Key::N; | ||||
| 		m_shift_keymap[0x32] = Key::B; | ||||
| 		m_shift_keymap[0x33] = Key::H; | ||||
| 		m_shift_keymap[0x34] = Key::G; | ||||
| 		m_shift_keymap[0x35] = Key::Y; | ||||
| 		m_shift_keymap[0x36] = Key::Ampersand; | ||||
| 		m_shift_keymap[0x3A] = Key::M; | ||||
| 		m_shift_keymap[0x3B] = Key::J; | ||||
| 		m_shift_keymap[0x3C] = Key::U; | ||||
| 		m_shift_keymap[0x3D] = Key::Slash; | ||||
| 		m_shift_keymap[0x3E] = Key::OpenBracet; | ||||
| 		m_shift_keymap[0x41] = Key::Semicolon; | ||||
| 		m_shift_keymap[0x42] = Key::K; | ||||
| 		m_shift_keymap[0x43] = Key::I; | ||||
| 		m_shift_keymap[0x44] = Key::O; | ||||
| 		m_shift_keymap[0x45] = Key::Equals; | ||||
| 		m_shift_keymap[0x46] = Key::CloseBracet; | ||||
| 		m_shift_keymap[0x49] = Key::Period; | ||||
| 		m_shift_keymap[0x4A] = Key::Hyphen; | ||||
| 		m_shift_keymap[0x4B] = Key::L; | ||||
| 		m_shift_keymap[0x4C] = Key::O_Umlaut; | ||||
| 		m_shift_keymap[0x4D] = Key::P; | ||||
| 		m_shift_keymap[0x4E] = Key::QuestionMark; | ||||
| 		m_shift_keymap[0x52] = Key::A_Umlaut; | ||||
| 		m_shift_keymap[0x54] = Key::A_Ring; | ||||
| 		m_shift_keymap[0x55] = Key::BackTick; | ||||
| 		m_shift_keymap[0x58] = Key::CapsLock; | ||||
| 		m_shift_keymap[0x59] = Key::RightShift; | ||||
| 		m_shift_keymap[0x59] = Key::RightShift; | ||||
| 		m_shift_keymap[0x5A] = Key::Enter; | ||||
| 		m_shift_keymap[0x5B] = Key::Caret; | ||||
| 		m_shift_keymap[0x5D] = Key::Asterix; | ||||
| 		m_shift_keymap[0x61] = Key::GreaterThan; | ||||
| 		m_shift_keymap[0x66] = Key::Backspace; | ||||
| 		m_shift_keymap[0x69] = Key::Numpad1; | ||||
| 		m_shift_keymap[0x6B] = Key::Numpad4; | ||||
| 		m_shift_keymap[0x6C] = Key::Numpad7; | ||||
| 		m_shift_keymap[0x70] = Key::Numpad0; | ||||
| 		m_shift_keymap[0x71] = Key::NumpadDecimal; | ||||
| 		m_shift_keymap[0x72] = Key::Numpad2; | ||||
| 		m_shift_keymap[0x73] = Key::Numpad5; | ||||
| 		m_shift_keymap[0x74] = Key::Numpad6; | ||||
| 		m_shift_keymap[0x75] = Key::Numpad8; | ||||
| 		m_shift_keymap[0x76] = Key::Escape; | ||||
| 		m_shift_keymap[0x77] = Key::NumLock; | ||||
| 		m_shift_keymap[0x78] = Key::F11; | ||||
| 		m_shift_keymap[0x79] = Key::NumpadPlus; | ||||
| 		m_shift_keymap[0x7A] = Key::Numpad3; | ||||
| 		m_shift_keymap[0x7B] = Key::NumpadMinus; | ||||
| 		m_shift_keymap[0x7C] = Key::NumpadMultiply; | ||||
| 		m_shift_keymap[0x7D] = Key::Numpad9; | ||||
| 		m_shift_keymap[0x83] = Key::F7; | ||||
| 
 | ||||
| 		MUST(m_altgr_keymap.resize(0xFF, Key::Invalid)); | ||||
| 		m_altgr_keymap[0x01] = Key::F9; | ||||
| 		m_altgr_keymap[0x03] = Key::F5; | ||||
| 		m_altgr_keymap[0x04] = Key::F3; | ||||
| 		m_altgr_keymap[0x05] = Key::F1; | ||||
| 		m_altgr_keymap[0x06] = Key::F2; | ||||
| 		m_altgr_keymap[0x07] = Key::F11; | ||||
| 		m_altgr_keymap[0x09] = Key::F10; | ||||
| 		m_altgr_keymap[0x0A] = Key::F8; | ||||
| 		m_altgr_keymap[0x0B] = Key::F6; | ||||
| 		m_altgr_keymap[0x0C] = Key::F4; | ||||
| 		m_altgr_keymap[0x0D] = Key::Tab; | ||||
| 		m_altgr_keymap[0x0E] = Key::None; | ||||
| 		m_altgr_keymap[0x11] = Key::Alt; | ||||
| 		m_altgr_keymap[0x12] = Key::LeftShift; | ||||
| 		m_altgr_keymap[0x14] = Key::LeftCtrl; | ||||
| 		m_altgr_keymap[0x15] = Key::Q; | ||||
| 		m_altgr_keymap[0x16] = Key::None; | ||||
| 		m_altgr_keymap[0x1A] = Key::Z; | ||||
| 		m_altgr_keymap[0x1B] = Key::S; | ||||
| 		m_altgr_keymap[0x1C] = Key::A; | ||||
| 		m_altgr_keymap[0x1D] = Key::W; | ||||
| 		m_altgr_keymap[0x1E] = Key::AtSign; | ||||
| 		m_altgr_keymap[0x21] = Key::C; | ||||
| 		m_altgr_keymap[0x22] = Key::X; | ||||
| 		m_altgr_keymap[0x23] = Key::D; | ||||
| 		m_altgr_keymap[0x24] = Key::E; | ||||
| 		m_altgr_keymap[0x25] = Key::Dollar; | ||||
| 		m_altgr_keymap[0x26] = Key::Pound; | ||||
| 		m_altgr_keymap[0x29] = Key::Space; | ||||
| 		m_altgr_keymap[0x2A] = Key::V; | ||||
| 		m_altgr_keymap[0x2B] = Key::F; | ||||
| 		m_altgr_keymap[0x2C] = Key::T; | ||||
| 		m_altgr_keymap[0x2D] = Key::R; | ||||
| 		m_altgr_keymap[0x2E] = Key::None; | ||||
| 		m_altgr_keymap[0x31] = Key::N; | ||||
| 		m_altgr_keymap[0x32] = Key::B; | ||||
| 		m_altgr_keymap[0x33] = Key::H; | ||||
| 		m_altgr_keymap[0x34] = Key::G; | ||||
| 		m_altgr_keymap[0x35] = Key::Y; | ||||
| 		m_altgr_keymap[0x36] = Key::None; | ||||
| 		m_altgr_keymap[0x3A] = Key::M; | ||||
| 		m_altgr_keymap[0x3B] = Key::J; | ||||
| 		m_altgr_keymap[0x3C] = Key::U; | ||||
| 		m_altgr_keymap[0x3D] = Key::OpenCurlyBrace; | ||||
| 		m_altgr_keymap[0x3E] = Key::OpenBrace; | ||||
| 		m_altgr_keymap[0x41] = Key::None; | ||||
| 		m_altgr_keymap[0x42] = Key::K; | ||||
| 		m_altgr_keymap[0x43] = Key::I; | ||||
| 		m_altgr_keymap[0x44] = Key::O; | ||||
| 		m_altgr_keymap[0x45] = Key::CloseCurlyBrace; | ||||
| 		m_altgr_keymap[0x46] = Key::CloseBrace; | ||||
| 		m_altgr_keymap[0x49] = Key::None; | ||||
| 		m_altgr_keymap[0x4A] = Key::None; | ||||
| 		m_altgr_keymap[0x4B] = Key::L; | ||||
| 		m_altgr_keymap[0x4C] = Key::O_Umlaut; | ||||
| 		m_altgr_keymap[0x4D] = Key::P; | ||||
| 		m_altgr_keymap[0x4E] = Key::BackSlash; | ||||
| 		m_altgr_keymap[0x52] = Key::A_Umlaut; | ||||
| 		m_altgr_keymap[0x54] = Key::A_Ring; | ||||
| 		m_altgr_keymap[0x55] = Key::None; | ||||
| 		m_altgr_keymap[0x58] = Key::CapsLock; | ||||
| 		m_altgr_keymap[0x59] = Key::RightShift; | ||||
| 		m_altgr_keymap[0x59] = Key::RightShift; | ||||
| 		m_altgr_keymap[0x5A] = Key::Enter; | ||||
| 		m_altgr_keymap[0x5B] = Key::Tilde; | ||||
| 		m_altgr_keymap[0x5D] = Key::None; | ||||
| 		m_altgr_keymap[0x61] = Key::Pipe; | ||||
| 		m_altgr_keymap[0x66] = Key::Backspace; | ||||
| 		m_altgr_keymap[0x69] = Key::Numpad1; | ||||
| 		m_altgr_keymap[0x6B] = Key::Numpad4; | ||||
| 		m_altgr_keymap[0x6C] = Key::Numpad7; | ||||
| 		m_altgr_keymap[0x70] = Key::Numpad0; | ||||
| 		m_altgr_keymap[0x71] = Key::NumpadDecimal; | ||||
| 		m_altgr_keymap[0x72] = Key::Numpad2; | ||||
| 		m_altgr_keymap[0x73] = Key::Numpad5; | ||||
| 		m_altgr_keymap[0x74] = Key::Numpad6; | ||||
| 		m_altgr_keymap[0x75] = Key::Numpad8; | ||||
| 		m_altgr_keymap[0x76] = Key::Escape; | ||||
| 		m_altgr_keymap[0x77] = Key::NumLock; | ||||
| 		m_altgr_keymap[0x78] = Key::F11; | ||||
| 		m_altgr_keymap[0x79] = Key::NumpadPlus; | ||||
| 		m_altgr_keymap[0x7A] = Key::Numpad3; | ||||
| 		m_altgr_keymap[0x7B] = Key::NumpadMinus; | ||||
| 		m_altgr_keymap[0x7C] = Key::NumpadMultiply; | ||||
| 		m_altgr_keymap[0x7D] = Key::Numpad9; | ||||
| 		m_altgr_keymap[0x83] = Key::F7; | ||||
| 
 | ||||
| 		MUST(m_extended_keymap.resize(0xFF, Key::Invalid)); | ||||
| 		m_extended_keymap[0x11] = Key::AltGr; | ||||
| 		m_extended_keymap[0x14] = Key::RightCtrl; | ||||
| 		m_extended_keymap[0x15] = Key::MediaPrevious; | ||||
| 		m_extended_keymap[0x1F] = Key::Super; | ||||
| 		m_extended_keymap[0x21] = Key::VolumeUp; | ||||
| 		m_extended_keymap[0x23] = Key::VolumeMute; | ||||
| 		m_extended_keymap[0x2B] = Key::Calculator; | ||||
| 		m_extended_keymap[0x32] = Key::VolumeDown; | ||||
| 		m_extended_keymap[0x34] = Key::MediaPlayPause; | ||||
| 		m_extended_keymap[0x3B] = Key::MediaStop; | ||||
| 		m_extended_keymap[0x4A] = Key::NumpadDivide; | ||||
| 		m_extended_keymap[0x4D] = Key::MediaNext; | ||||
| 		m_extended_keymap[0x5A] = Key::NumpadEnter; | ||||
| 		m_extended_keymap[0x69] = Key::End; | ||||
| 		m_extended_keymap[0x6B] = Key::ArrowLeft; | ||||
| 		m_extended_keymap[0x6C] = Key::Home; | ||||
| 		m_extended_keymap[0x70] = Key::Insert; | ||||
| 		m_extended_keymap[0x71] = Key::Delete; | ||||
| 		m_extended_keymap[0x72] = Key::ArrowDown; | ||||
| 		m_extended_keymap[0x74] = Key::ArrowRight; | ||||
| 		m_extended_keymap[0x75] = Key::ArrowUp; | ||||
| 		m_extended_keymap[0x7A] = Key::PageUp; | ||||
| 		m_extended_keymap[0x7D] = Key::PageDown; | ||||
| 	} | ||||
| 
 | ||||
| 	Key PS2Keymap::key_for_scancode_and_modifiers(uint32_t scancode, uint8_t modifiers) | ||||
| 	{ | ||||
| 		bool extended = scancode & 0x80000000; | ||||
| 		scancode &= 0x7FFFFFFF; | ||||
| 
 | ||||
| 		KeyEvent dummy; | ||||
| 		dummy.modifier = modifiers; | ||||
| 		auto& keymap =	extended      ? m_extended_keymap : | ||||
| 						dummy.shift() ? m_shift_keymap : | ||||
| 						dummy.altgr() ? m_altgr_keymap : | ||||
| 										m_normal_keymap; | ||||
| 
 | ||||
| 		if (scancode >= keymap.size()) | ||||
| 			return Key::Invalid; | ||||
| 
 | ||||
| 		Key key = keymap[scancode]; | ||||
| 
 | ||||
| 		if (dummy.num_lock() && !(dummy.shift() || dummy.ctrl() || dummy.alt())) | ||||
| 		{ | ||||
| 			switch (key) | ||||
| 			{ | ||||
| 				case Key::Numpad0: | ||||
| 					key = Key::Insert; | ||||
| 					break; | ||||
| 				case Key::Numpad1: | ||||
| 					key = Key::End; | ||||
| 					break; | ||||
| 				case Key::Numpad2: | ||||
| 					key = Key::ArrowDown; | ||||
| 					break; | ||||
| 				case Key::Numpad3: | ||||
| 					key = Key::PageDown; | ||||
| 					break; | ||||
| 				case Key::Numpad4: | ||||
| 					key = Key::ArrowLeft; | ||||
| 					break; | ||||
| 				case Key::Numpad5: | ||||
| 					key = Key::None; | ||||
| 					break; | ||||
| 				case Key::Numpad6: | ||||
| 					key = Key::ArrowRight; | ||||
| 					break; | ||||
| 				case Key::Numpad7: | ||||
| 					key = Key::Home; | ||||
| 					break; | ||||
| 				case Key::Numpad8: | ||||
| 					key = Key::ArrowUp; | ||||
| 					break; | ||||
| 				case Key::Numpad9: | ||||
| 					key = Key::PageUp; | ||||
| 					break; | ||||
| 				case Key::NumpadDecimal: | ||||
| 					key = Key::Delete; | ||||
| 					break; | ||||
| 				default: | ||||
| 					break; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return keymap[scancode]; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -3,7 +3,7 @@ | |||
| #include <BAN/StringView.h> | ||||
| #include <BAN/Vector.h> | ||||
| #include <kernel/CPUID.h> | ||||
| #include <kernel/Input.h> | ||||
| #include <kernel/Device.h> | ||||
| #include <kernel/IO.h> | ||||
| #include <kernel/PIT.h> | ||||
| #include <kernel/PCI.h> | ||||
|  | @ -25,7 +25,6 @@ namespace Kernel | |||
| 	Shell::Shell(TTY* tty) | ||||
| 		: m_tty(tty) | ||||
| 	{ | ||||
| 		Input::register_key_event_callback({ &Shell::key_event_callback, this }); | ||||
| 		MUST(set_prompt(s_default_prompt)); | ||||
| 		MUST(m_buffer.push_back(""sv)); | ||||
| 	} | ||||
|  | @ -83,8 +82,9 @@ namespace Kernel | |||
| 		TTY_PRINT("{}", m_prompt); | ||||
| 		for (;;) | ||||
| 		{ | ||||
| 			PIT::sleep(1); // sleep until next reschedule
 | ||||
| 			Input::update(); | ||||
| 			Input::KeyEvent event; | ||||
| 			MUST(((CharacterDevice*)DeviceManager::get().devices()[0])->read({ (uint8_t*)&event, sizeof(event) })); | ||||
| 			key_event_callback(event); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -560,7 +560,7 @@ argument_done: | |||
| 
 | ||||
| 	void Shell::key_event_callback(Input::KeyEvent event) | ||||
| 	{ | ||||
| 		if (!event.pressed) | ||||
| 		if (event.released()) | ||||
| 			return; | ||||
| 
 | ||||
| 		BAN::String& current_buffer = m_buffer[m_cursor_pos.line]; | ||||
|  | @ -606,7 +606,7 @@ argument_done: | |||
| 			case Input::Key::Tab: | ||||
| 				break; | ||||
| 			 | ||||
| 			case Input::Key::Left: | ||||
| 			case Input::Key::ArrowLeft: | ||||
| 				if (m_cursor_pos.index > 0) | ||||
| 				{					 | ||||
| 					uint32_t len = get_last_length(current_buffer.sv().substring(0, m_cursor_pos.index)); | ||||
|  | @ -615,7 +615,7 @@ argument_done: | |||
| 				} | ||||
| 				break; | ||||
| 
 | ||||
| 			case Input::Key::Right: | ||||
| 			case Input::Key::ArrowRight: | ||||
| 				if (m_cursor_pos.index < current_buffer.size()) | ||||
| 				{ | ||||
| 					uint32_t len = get_next_length(current_buffer.sv().substring(m_cursor_pos.index)); | ||||
|  | @ -624,7 +624,7 @@ argument_done: | |||
| 				} | ||||
| 				break; | ||||
| 
 | ||||
| 			case Input::Key::Up: | ||||
| 			case Input::Key::ArrowUp: | ||||
| 				if (m_cursor_pos.line > 0) | ||||
| 				{ | ||||
| 					const auto& new_buffer = m_buffer[m_cursor_pos.line - 1]; | ||||
|  | @ -635,7 +635,7 @@ argument_done: | |||
| 				} | ||||
| 				break; | ||||
| 
 | ||||
| 			case Input::Key::Down: | ||||
| 			case Input::Key::ArrowDown: | ||||
| 				if (m_cursor_pos.line < m_buffer.size() - 1) | ||||
| 				{ | ||||
| 					const auto& new_buffer = m_buffer[m_cursor_pos.line + 1]; | ||||
|  | @ -647,7 +647,7 @@ argument_done: | |||
| 				break; | ||||
| 
 | ||||
| 			case Input::Key::A: | ||||
| 				if (event.modifiers & 2) | ||||
| 				if (event.ctrl()) | ||||
| 				{ | ||||
| 					m_cursor_pos.col = m_cursor_pos.index = 0; | ||||
| 					break; | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ | |||
| #include <kernel/FS/VirtualFileSystem.h> | ||||
| #include <kernel/GDT.h> | ||||
| #include <kernel/IDT.h> | ||||
| #include <kernel/Input.h> | ||||
| #include <kernel/Input/PS2Controller.h> | ||||
| #include <kernel/InterruptController.h> | ||||
| #include <kernel/kmalloc.h> | ||||
| #include <kernel/kprint.h> | ||||
|  | @ -88,6 +88,7 @@ extern "C" uintptr_t g_userspace_end; | |||
| extern void userspace_entry(); | ||||
| 
 | ||||
| void init2(void*); | ||||
| void device_updater(void*); | ||||
| 
 | ||||
| extern "C" void kernel_main() | ||||
| { | ||||
|  | @ -136,10 +137,6 @@ extern "C" void kernel_main() | |||
| 	PIT::initialize(); | ||||
| 	dprintln("PIT initialized"); | ||||
| 
 | ||||
| 	if (!Input::initialize()) | ||||
| 		dprintln("Could not initialize input drivers"); | ||||
| 	dprintln("Input initialized"); | ||||
| 
 | ||||
| 	MUST(Scheduler::initialize()); | ||||
| 	Scheduler& scheduler = Scheduler::get(); | ||||
| #if 0 
 | ||||
|  | @ -186,15 +183,26 @@ extern "C" void kernel_main() | |||
| 		} | ||||
| 	)))); | ||||
| #else | ||||
| 	MUST(scheduler.add_thread(MUST(Thread::create(init2, tty1, nullptr)))); | ||||
| 	MUST(scheduler.add_thread(MUST(Thread::create(init2, tty1)))); | ||||
| 	MUST(scheduler.add_thread(MUST(Thread::create(device_updater)))); | ||||
| #endif | ||||
| 	scheduler.start(); | ||||
| 	ASSERT(false); | ||||
| } | ||||
| 
 | ||||
| void device_updater(void*) | ||||
| { | ||||
| 	while (true) | ||||
| 	{ | ||||
| 		Kernel::DeviceManager::get().update(); | ||||
| 		PIT::sleep(1); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void init2(void* tty1_ptr) | ||||
| { | ||||
| 	using namespace Kernel; | ||||
| 	using namespace Kernel::Input; | ||||
| 
 | ||||
| 	TTY* tty1 = (TTY*)tty1_ptr; | ||||
| 
 | ||||
|  | @ -202,6 +210,9 @@ void init2(void* tty1_ptr) | |||
| 	if (auto res = VirtualFileSystem::get().mount_test(); res.is_error()) | ||||
| 		dwarnln("{}", res.error()); | ||||
| 
 | ||||
| 	if (auto res = PS2Controller::initialize(); res.is_error()) | ||||
| 		dprintln("{}", res.error()); | ||||
| 
 | ||||
| 	MUST(Process::create_kernel( | ||||
| 		[](void* tty1)  | ||||
| 		{ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue