Kernel: DeviceManager is now a 'FileSystem' so it can expose devices
Shell reads keyboard through /dev/input :)
This commit is contained in:
		
							parent
							
								
									f4db246658
								
							
						
					
					
						commit
						a24c2d9be2
					
				|  | @ -1,15 +1,18 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/StringView.h> | ||||
| #include <BAN/Vector.h> | ||||
| #include <kernel/FS/FileSystem.h> | ||||
| #include <kernel/FS/Inode.h> | ||||
| #include <kernel/SpinLock.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	class Device | ||||
| 	class Device : public Inode | ||||
| 	{ | ||||
| 	public: | ||||
| 		enum class Type | ||||
| 		enum class DeviceType | ||||
| 		{ | ||||
| 			BlockDevice, | ||||
| 			CharacterDevice, | ||||
|  | @ -17,36 +20,59 @@ namespace Kernel | |||
| 		}; | ||||
| 
 | ||||
| 		virtual ~Device() {} | ||||
| 		virtual Type type() const = 0; | ||||
| 		virtual DeviceType device_type() const = 0; | ||||
| 		virtual void update() {} | ||||
| 	}; | ||||
| 
 | ||||
| 	class BlockDevice : public Device | ||||
| 	{ | ||||
| 	public: | ||||
| 		virtual Type type() const override { return Type::BlockDevice; } | ||||
| 		virtual DeviceType device_type() const override { return DeviceType::BlockDevice; } | ||||
| 	}; | ||||
| 
 | ||||
| 	class CharacterDevice : public Device | ||||
| 	{ | ||||
| 	public: | ||||
| 		virtual Type type() const override { return Type::CharacterDevice; } | ||||
| 
 | ||||
| 		virtual BAN::ErrorOr<void> read(BAN::Span<uint8_t>); | ||||
| 		virtual DeviceType device_type() const override { return DeviceType::CharacterDevice; } | ||||
| 	}; | ||||
| 
 | ||||
| 	class DeviceManager | ||||
| 	class DeviceManager final : public FileSystem, public Inode | ||||
| 	{ | ||||
| 		BAN_NON_COPYABLE(DeviceManager); | ||||
| 		BAN_NON_MOVABLE(DeviceManager); | ||||
| 
 | ||||
| 	public: | ||||
| 		static void initialize(); | ||||
| 		static DeviceManager& get(); | ||||
| 
 | ||||
| 		void update(); | ||||
| 		void add_device(Device*); | ||||
| 
 | ||||
| 		BAN::Vector<Device*> devices() { return m_devices; } | ||||
| 		virtual ino_t ino() const override { return 0; } | ||||
| 		virtual mode_t mode() const override { return IFDIR | IRUSR | IWUSR | IXUSR | IRGRP | IXGRP | IROTH | IXOTH; } | ||||
| 		virtual nlink_t nlink() const override { return 0; } | ||||
| 		virtual uid_t uid() const override { return 0; } | ||||
| 		virtual gid_t gid() const override { return 0; } | ||||
| 		virtual off_t size() const override { return 0; } | ||||
| 		virtual timespec atime() const override { return { 0, 0 }; } | ||||
| 		virtual timespec mtime() const override { return { 0, 0 }; } | ||||
| 		virtual timespec ctime() const override { return { 0, 0 }; } | ||||
| 		virtual blksize_t blksize() const override { return 0; } | ||||
| 		virtual blkcnt_t blocks() const override { return 0; } | ||||
| 
 | ||||
| 		virtual BAN::StringView name() const override { return "device-manager"sv; } | ||||
| 
 | ||||
| 		virtual BAN::ErrorOr<size_t> read(size_t, void*, size_t) override { return BAN::Error::from_errno(EISDIR); } | ||||
| 		virtual BAN::ErrorOr<void> create_file(BAN::StringView, mode_t) override { return BAN::Error::from_errno(EINVAL); }; | ||||
| 
 | ||||
| 		virtual Type type() const override { return Type::DeviceManager; } | ||||
| 		virtual bool operator==(const Inode&) const override { return false; } | ||||
| 
 | ||||
| 		virtual BAN::RefPtr<Inode> root_inode() override { return this; } | ||||
| 
 | ||||
| 	protected: | ||||
| 		virtual BAN::ErrorOr<BAN::RefPtr<Inode>> read_directory_inode_impl(BAN::StringView) override; | ||||
| 		virtual BAN::ErrorOr<BAN::Vector<BAN::String>> read_directory_entries_impl(size_t) override; | ||||
| 
 | ||||
| 	private: | ||||
| 		DeviceManager() = default; | ||||
|  | @ -54,6 +80,8 @@ namespace Kernel | |||
| 	private: | ||||
| 		SpinLock m_lock; | ||||
| 		BAN::Vector<Device*> m_devices; | ||||
| 
 | ||||
| 		friend class BAN::RefPtr<DeviceManager>; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -35,6 +35,8 @@ namespace Kernel | |||
| 
 | ||||
| 		enum class Type | ||||
| 		{ | ||||
| 			DeviceManager, | ||||
| 			Device, | ||||
| 			Ext2, | ||||
| 		}; | ||||
| 
 | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ namespace Kernel | |||
| 		virtual BAN::RefPtr<Inode> root_inode() override  { return m_root_inode; } | ||||
| 
 | ||||
| 		BAN::ErrorOr<void> mount_test(); | ||||
| 		BAN::ErrorOr<void> mount(FileSystem*, BAN::StringView); | ||||
| 
 | ||||
| 		struct File | ||||
| 		{ | ||||
|  |  | |||
|  | @ -31,8 +31,6 @@ namespace Kernel::Input | |||
| 		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) | ||||
|  | @ -59,6 +57,31 @@ namespace Kernel::Input | |||
| 		PS2Keymap m_keymap; | ||||
| 
 | ||||
| 		State m_state { State::Normal }; | ||||
| 
 | ||||
| 	public: | ||||
| 		virtual ino_t ino() const override { return 0; } | ||||
| 		virtual mode_t mode() const override { return IFCHR | IRUSR | IRGRP; } | ||||
| 		virtual nlink_t nlink() const override { return 0; } | ||||
| 		virtual uid_t uid() const override { return 0; } | ||||
| 		virtual gid_t gid() const override { return 0; } | ||||
| 		virtual off_t size() const override { return 0; } | ||||
| 		virtual timespec atime() const override { return { 0, 0 }; } | ||||
| 		virtual timespec mtime() const override { return { 0, 0 }; } | ||||
| 		virtual timespec ctime() const override { return { 0, 0 }; } | ||||
| 		virtual blksize_t blksize() const override { return sizeof(KeyEvent); } | ||||
| 		virtual blkcnt_t blocks() const override { return 0; } | ||||
| 
 | ||||
| 		virtual BAN::StringView name() const override { return "input"sv; } | ||||
| 
 | ||||
| 		virtual BAN::ErrorOr<size_t> read(size_t, void*, size_t) override; | ||||
| 		virtual BAN::ErrorOr<void> create_file(BAN::StringView, mode_t) override { return BAN::Error::from_errno(ENOTDIR); } | ||||
| 
 | ||||
| 		virtual Type type() const override { return Type::Device; } | ||||
| 		virtual bool operator==(const Inode&) const override { return false; } | ||||
| 
 | ||||
| 	protected: | ||||
| 		virtual BAN::ErrorOr<BAN::RefPtr<Inode>> read_directory_inode_impl(BAN::StringView) override { return BAN::Error::from_errno(ENOTDIR); } | ||||
| 		virtual BAN::ErrorOr<BAN::Vector<BAN::String>> read_directory_entries_impl(size_t) override { return BAN::Error::from_errno(ENOTDIR); } | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -1,13 +1,35 @@ | |||
| #include <kernel/Device.h> | ||||
| #include <kernel/LockGuard.h> | ||||
| #include <kernel/Process.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	static DeviceManager* s_instance = nullptr; | ||||
| 
 | ||||
| 	void DeviceManager::initialize() | ||||
| 	{ | ||||
| 		ASSERT(s_instance == nullptr); | ||||
| 
 | ||||
| 		s_instance = new DeviceManager; | ||||
| 		ASSERT(s_instance != nullptr); | ||||
| 		 | ||||
| 		MUST(Process::create_kernel( | ||||
| 			[](void*) | ||||
| 			{ | ||||
| 				while (true) | ||||
| 				{ | ||||
| 					DeviceManager::get().update(); | ||||
| 					PIT::sleep(1); | ||||
| 				} | ||||
| 			}, nullptr) | ||||
| 		); | ||||
| 	} | ||||
| 
 | ||||
| 	DeviceManager& DeviceManager::get() | ||||
| 	{ | ||||
| 		static DeviceManager instance; | ||||
| 		return instance; | ||||
| 		ASSERT(s_instance); | ||||
| 		return *s_instance; | ||||
| 	} | ||||
| 
 | ||||
| 	void DeviceManager::update() | ||||
|  | @ -23,4 +45,26 @@ namespace Kernel | |||
| 		MUST(m_devices.push_back(device)); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<BAN::RefPtr<Inode>> DeviceManager::read_directory_inode_impl(BAN::StringView name) | ||||
| 	{ | ||||
| 		LockGuard _(m_lock); | ||||
| 		for (Device* device : m_devices) | ||||
| 			if (device->name() == name) | ||||
| 				return BAN::RefPtr<Inode>(device); | ||||
| 		return BAN::Error::from_errno(ENOENT); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<BAN::Vector<BAN::String>> DeviceManager::read_directory_entries_impl(size_t index) | ||||
| 	{ | ||||
| 		BAN::Vector<BAN::String> result; | ||||
| 		if (index > 0) | ||||
| 			return result; | ||||
| 
 | ||||
| 		LockGuard _(m_lock); | ||||
| 		TRY(result.reserve(m_devices.size())); | ||||
| 		for (Device* device : m_devices) | ||||
| 			TRY(result.emplace_back(device->name())); | ||||
| 		return result; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -1,5 +1,6 @@ | |||
| #include <BAN/StringView.h> | ||||
| #include <BAN/Vector.h> | ||||
| #include <kernel/Device.h> | ||||
| #include <kernel/FS/Ext2.h> | ||||
| #include <kernel/FS/VirtualFileSystem.h> | ||||
| #include <kernel/PCI.h> | ||||
|  | @ -112,15 +113,14 @@ namespace Kernel | |||
| 
 | ||||
| 		if (!root_inode()) | ||||
| 			derrorln("Could not locate root partition"); | ||||
| 
 | ||||
| 		TRY(mount(&DeviceManager::get(), "/dev")); | ||||
| 
 | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> VirtualFileSystem::mount_test() | ||||
| 	{ | ||||
| 		auto mount = TRY(root_inode()->read_directory_inode("mnt"sv)); | ||||
| 		if (!mount->ifdir()) | ||||
| 			return BAN::Error::from_errno(ENOTDIR); | ||||
| 
 | ||||
| 		for (auto* controller : m_storage_controllers) | ||||
| 		{ | ||||
| 			for (auto* device : controller->devices()) | ||||
|  | @ -130,12 +130,21 @@ namespace Kernel | |||
| 					if (partition.name() == "mount-test"sv) | ||||
| 					{ | ||||
| 						auto ext2fs = TRY(Ext2FS::create(partition)); | ||||
| 						TRY(m_mount_points.push_back({ mount, ext2fs })); | ||||
| 						TRY(mount(ext2fs, "/mnt"sv)); | ||||
| 						return {}; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		return BAN::Error::from_c_string("Could not find mount-test partition"); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> VirtualFileSystem::mount(FileSystem* file_system, BAN::StringView path) | ||||
| 	{ | ||||
| 		auto file = TRY(file_from_absolute_path(path)); | ||||
| 		if (!file.inode->ifdir()) | ||||
| 			return BAN::Error::from_errno(ENOTDIR); | ||||
| 		TRY(m_mount_points.push_back({ file.inode, file_system })); | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -226,19 +226,19 @@ namespace Kernel::Input | |||
| 		append_command_queue(Command::SET_LEDS, new_leds); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> PS2Keyboard::read(BAN::Span<uint8_t> output) | ||||
| 	BAN::ErrorOr<size_t> PS2Keyboard::read(size_t, void* buffer, size_t size) | ||||
| 	{ | ||||
| 		if (output.size() < sizeof(Input::KeyEvent)) | ||||
| 			return BAN::Error::from_c_string("Too small buffer for KeyEvent"); | ||||
| 		if (size < sizeof(KeyEvent)) | ||||
| 			return BAN::Error::from_errno(ENOBUFS); | ||||
| 
 | ||||
| 		while (m_event_queue.empty()) | ||||
| 			PIT::sleep(1); | ||||
| 
 | ||||
| 		CriticalScope _; | ||||
| 		*(Input::KeyEvent*)output.data() = m_event_queue.front(); | ||||
| 		*(KeyEvent*)buffer = m_event_queue.front(); | ||||
| 		m_event_queue.pop(); | ||||
| 
 | ||||
| 		return {}; | ||||
| 		return sizeof(KeyEvent); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -79,11 +79,13 @@ namespace Kernel | |||
| 
 | ||||
| 	void Shell::run() | ||||
| 	{ | ||||
| 		int fd = MUST(Process::current()->open("/dev/input"sv, O_RDONLY)); | ||||
| 
 | ||||
| 		TTY_PRINT("{}", m_prompt); | ||||
| 		for (;;) | ||||
| 		{ | ||||
| 			Input::KeyEvent event; | ||||
| 			MUST(((CharacterDevice*)DeviceManager::get().devices()[0])->read({ (uint8_t*)&event, sizeof(event) })); | ||||
| 			MUST(Process::current()->read(fd, &event, sizeof(event))); | ||||
| 			key_event_callback(event); | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
|  | @ -184,7 +184,6 @@ extern "C" void kernel_main() | |||
| 	)))); | ||||
| #else | ||||
| 	MUST(scheduler.add_thread(MUST(Thread::create(init2, tty1)))); | ||||
| 	MUST(scheduler.add_thread(MUST(Thread::create(device_updater)))); | ||||
| #endif | ||||
| 	scheduler.start(); | ||||
| 	ASSERT(false); | ||||
|  | @ -206,6 +205,8 @@ void init2(void* tty1_ptr) | |||
| 
 | ||||
| 	TTY* tty1 = (TTY*)tty1_ptr; | ||||
| 
 | ||||
| 	DeviceManager::initialize(); | ||||
| 
 | ||||
| 	MUST(VirtualFileSystem::initialize()); | ||||
| 	if (auto res = VirtualFileSystem::get().mount_test(); res.is_error()) | ||||
| 		dwarnln("{}", res.error()); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue