From: Tulio A M Mendes Date: Thu, 12 Feb 2026 07:01:14 +0000 (-0300) Subject: refactor: decouple DevFS from TTY/PTY drivers via device registration API X-Git-Url: https://projects.tadryanom.me/docs/static/git-logo.png?a=commitdiff_plain;h=497402d328dbc69eb47fcf1740e4379470e123b8;p=AdrOS.git refactor: decouple DevFS from TTY/PTY drivers via device registration API Added devfs_register_device() API so device drivers register their own fs_node_t with DevFS. DevFS is now a generic device registry that dispatches through function pointers — it no longer includes tty.h or pty.h and has zero knowledge of TTY/PTY internals. - tty.c: registers /dev/console and /dev/tty with VFS-compatible wrappers - pty.c: registers /dev/ptmx and /dev/pts (with finddir/readdir moved from devfs.c) - devfs.c: only owns built-in devices (null, zero, random, urandom); all other devices come from the registry This enables any future driver to register device nodes without modifying devfs.c. --- diff --git a/include/devfs.h b/include/devfs.h index ba6256d..24d475b 100644 --- a/include/devfs.h +++ b/include/devfs.h @@ -3,6 +3,16 @@ #include "fs.h" +#define DEVFS_MAX_DEVICES 32 + fs_node_t* devfs_create_root(void); +/* + * Register a device node with devfs. + * The caller owns the fs_node_t storage (must remain valid for the + * lifetime of the device). DevFS stores only a pointer. + * Returns 0 on success, -1 if the registry is full. + */ +int devfs_register_device(fs_node_t *node); + #endif diff --git a/src/kernel/devfs.c b/src/kernel/devfs.c index 444f176..4c815f8 100644 --- a/src/kernel/devfs.c +++ b/src/kernel/devfs.c @@ -1,8 +1,6 @@ #include "devfs.h" #include "errno.h" -#include "tty.h" -#include "pty.h" #include "utils.h" extern uint32_t get_tick_count(void); @@ -16,12 +14,19 @@ static fs_node_t g_dev_null; static fs_node_t g_dev_zero; static fs_node_t g_dev_random; static fs_node_t g_dev_urandom; -static fs_node_t g_dev_console; -static fs_node_t g_dev_tty; -static fs_node_t g_dev_ptmx; -static fs_node_t g_dev_pts_dir; static uint32_t g_devfs_inited = 0; +/* --- Device registry --- */ +static fs_node_t* g_registered[DEVFS_MAX_DEVICES]; +static int g_registered_count = 0; + +int devfs_register_device(fs_node_t *node) { + if (!node) return -1; + if (g_registered_count >= DEVFS_MAX_DEVICES) return -1; + g_registered[g_registered_count++] = node; + return 0; +} + static uint32_t prng_state = 0x12345678; static uint32_t dev_null_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { @@ -90,56 +95,6 @@ static uint32_t dev_random_write(fs_node_t* node, uint32_t offset, uint32_t size return size; } -static uint32_t dev_console_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { - (void)node; - (void)offset; - int rc = tty_read_kbuf(buffer, size); - if (rc < 0) return 0; - return (uint32_t)rc; -} - -static uint32_t dev_console_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) { - (void)node; - (void)offset; - int rc = tty_write_kbuf((const uint8_t*)buffer, size); - if (rc < 0) return 0; - return (uint32_t)rc; -} - -static uint32_t dev_tty_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { - (void)node; - (void)offset; - int rc = tty_read_kbuf(buffer, size); - if (rc < 0) return 0; - return (uint32_t)rc; -} - -static uint32_t dev_tty_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) { - (void)node; - (void)offset; - int rc = tty_write_kbuf((const uint8_t*)buffer, size); - if (rc < 0) return 0; - return (uint32_t)rc; -} - -static uint32_t dev_ptmx_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { - (void)offset; - int idx = pty_ino_to_idx(node->inode); - if (idx < 0) idx = 0; - int rc = pty_master_read_idx(idx, buffer, size); - if (rc < 0) return 0; - return (uint32_t)rc; -} - -static uint32_t dev_ptmx_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) { - (void)offset; - int idx = pty_ino_to_idx(node->inode); - if (idx < 0) idx = 0; - int rc = pty_master_write_idx(idx, buffer, size); - if (rc < 0) return 0; - return (uint32_t)rc; -} - static struct fs_node* devfs_finddir_impl(struct fs_node* node, const char* name) { (void)node; if (!name || name[0] == 0) return 0; @@ -148,24 +103,10 @@ static struct fs_node* devfs_finddir_impl(struct fs_node* node, const char* name if (strcmp(name, "zero") == 0) return &g_dev_zero; if (strcmp(name, "random") == 0) return &g_dev_random; if (strcmp(name, "urandom") == 0) return &g_dev_urandom; - if (strcmp(name, "console") == 0) return &g_dev_console; - if (strcmp(name, "tty") == 0) return &g_dev_tty; - if (strcmp(name, "ptmx") == 0) return &g_dev_ptmx; - if (strcmp(name, "pts") == 0) return &g_dev_pts_dir; - return 0; -} -static struct fs_node* devfs_pts_finddir_impl(struct fs_node* node, const char* name) { - (void)node; - if (!name || name[0] == 0) return 0; - int count = pty_pair_count(); - for (int i = 0; i < count; i++) { - char num[4]; - num[0] = '0' + (char)i; - num[1] = '\0'; - if (strcmp(name, num) == 0) { - return pty_get_slave_node(i); - } + for (int i = 0; i < g_registered_count; i++) { + if (strcmp(g_registered[i]->name, name) == 0) + return g_registered[i]; } return 0; } @@ -175,18 +116,16 @@ static int devfs_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* if (!inout_index || !buf) return -1; if (buf_len < sizeof(struct vfs_dirent)) return -1; - static const struct { const char* name; uint32_t ino; uint8_t type; } devs[] = { + /* Built-in devices (owned by devfs) */ + static const struct { const char* name; uint32_t ino; uint8_t type; } builtins[] = { { "null", 2, FS_CHARDEVICE }, { "zero", 7, FS_CHARDEVICE }, { "random", 8, FS_CHARDEVICE }, { "urandom", 9, FS_CHARDEVICE }, - { "console", 10, FS_CHARDEVICE }, - { "tty", 3, FS_CHARDEVICE }, - { "ptmx", 4, FS_CHARDEVICE }, - { "pts", 5, FS_DIRECTORY }, }; - enum { NDEVS = 8 }; + enum { NBUILTINS = 4 }; + uint32_t total = (uint32_t)(NBUILTINS + g_registered_count); uint32_t idx = *inout_index; uint32_t cap = buf_len / (uint32_t)sizeof(struct vfs_dirent); struct vfs_dirent* ents = (struct vfs_dirent*)buf; @@ -202,48 +141,17 @@ static int devfs_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* e.d_ino = 1; e.d_type = FS_DIRECTORY; strcpy(e.d_name, ".."); } else { uint32_t di = idx - 2; - if (di >= NDEVS) break; - e.d_ino = devs[di].ino; - e.d_type = devs[di].type; - strcpy(e.d_name, devs[di].name); - } - - e.d_reclen = (uint16_t)sizeof(e); - ents[written] = e; - written++; - idx++; - } - - *inout_index = idx; - return (int)(written * (uint32_t)sizeof(struct vfs_dirent)); -} - -static int devfs_pts_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* buf, uint32_t buf_len) { - (void)node; - if (!inout_index || !buf) return -1; - if (buf_len < sizeof(struct vfs_dirent)) return -1; - - int count = pty_pair_count(); - uint32_t idx = *inout_index; - uint32_t cap = buf_len / (uint32_t)sizeof(struct vfs_dirent); - struct vfs_dirent* ents = (struct vfs_dirent*)buf; - uint32_t written = 0; - - while (written < cap) { - struct vfs_dirent e; - memset(&e, 0, sizeof(e)); - - if (idx == 0) { - e.d_ino = 5; e.d_type = FS_DIRECTORY; strcpy(e.d_name, "."); - } else if (idx == 1) { - e.d_ino = 1; e.d_type = FS_DIRECTORY; strcpy(e.d_name, ".."); - } else { - int pi = (int)(idx - 2); - if (pi >= count) break; - e.d_ino = PTY_SLAVE_INO_BASE + (uint32_t)pi; - e.d_type = FS_CHARDEVICE; - e.d_name[0] = '0' + (char)pi; - e.d_name[1] = '\0'; + if (di >= total) break; + if (di < NBUILTINS) { + e.d_ino = builtins[di].ino; + e.d_type = builtins[di].type; + strcpy(e.d_name, builtins[di].name); + } else { + fs_node_t* rn = g_registered[di - NBUILTINS]; + e.d_ino = rn->inode; + e.d_type = (uint8_t)rn->flags; + strcpy(e.d_name, rn->name); + } } e.d_reclen = (uint16_t)sizeof(e); @@ -303,44 +211,6 @@ static void devfs_init_once(void) { g_dev_urandom.inode = 9; g_dev_urandom.read = &dev_random_read; g_dev_urandom.write = &dev_random_write; - - memset(&g_dev_console, 0, sizeof(g_dev_console)); - strcpy(g_dev_console.name, "console"); - g_dev_console.flags = FS_CHARDEVICE; - g_dev_console.inode = 10; - g_dev_console.read = &dev_console_read; - g_dev_console.write = &dev_console_write; - - memset(&g_dev_tty, 0, sizeof(g_dev_tty)); - strcpy(g_dev_tty.name, "tty"); - g_dev_tty.flags = FS_CHARDEVICE; - g_dev_tty.inode = 3; - g_dev_tty.length = 0; - g_dev_tty.read = &dev_tty_read; - g_dev_tty.write = &dev_tty_write; - g_dev_tty.open = 0; - g_dev_tty.close = 0; - g_dev_tty.finddir = 0; - - memset(&g_dev_ptmx, 0, sizeof(g_dev_ptmx)); - strcpy(g_dev_ptmx.name, "ptmx"); - g_dev_ptmx.flags = FS_CHARDEVICE; - g_dev_ptmx.inode = PTY_MASTER_INO_BASE; - g_dev_ptmx.read = &dev_ptmx_read; - g_dev_ptmx.write = &dev_ptmx_write; - - memset(&g_dev_pts_dir, 0, sizeof(g_dev_pts_dir)); - strcpy(g_dev_pts_dir.name, "pts"); - g_dev_pts_dir.flags = FS_DIRECTORY; - g_dev_pts_dir.inode = 5; - g_dev_pts_dir.length = 0; - g_dev_pts_dir.read = 0; - g_dev_pts_dir.write = 0; - g_dev_pts_dir.open = 0; - g_dev_pts_dir.close = 0; - g_dev_pts_dir.finddir = &devfs_pts_finddir_impl; - g_dev_pts_dir.readdir = &devfs_pts_readdir_impl; - } fs_node_t* devfs_create_root(void) { diff --git a/src/kernel/pty.c b/src/kernel/pty.c index 617d62e..52282f9 100644 --- a/src/kernel/pty.c +++ b/src/kernel/pty.c @@ -1,5 +1,6 @@ #include "pty.h" +#include "devfs.h" #include "errno.h" #include "process.h" #include "waitqueue.h" @@ -101,12 +102,106 @@ static void pty_init_pair(int idx) { p->slave_node.write = &pty_slave_write_fn; } +/* --- DevFS pts directory callbacks --- */ + +static fs_node_t g_dev_ptmx_node; +static fs_node_t g_dev_pts_dir_node; + +static uint32_t pty_ptmx_read_fn(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { + (void)offset; + int idx = pty_ino_to_idx(node->inode); + if (idx < 0) idx = 0; + int rc = pty_master_read_idx(idx, buffer, size); + if (rc < 0) return 0; + return (uint32_t)rc; +} + +static uint32_t pty_ptmx_write_fn(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) { + (void)offset; + int idx = pty_ino_to_idx(node->inode); + if (idx < 0) idx = 0; + int rc = pty_master_write_idx(idx, buffer, size); + if (rc < 0) return 0; + return (uint32_t)rc; +} + +static struct fs_node* pty_pts_finddir(struct fs_node* node, const char* name) { + (void)node; + if (!name || name[0] == 0) return 0; + int count = pty_pair_count(); + for (int i = 0; i < count; i++) { + char num[4]; + num[0] = '0' + (char)i; + num[1] = '\0'; + if (strcmp(name, num) == 0) { + return pty_get_slave_node(i); + } + } + return 0; +} + +static int pty_pts_readdir(struct fs_node* node, uint32_t* inout_index, void* buf, uint32_t buf_len) { + (void)node; + if (!inout_index || !buf) return -1; + if (buf_len < sizeof(struct vfs_dirent)) return -1; + + int count = pty_pair_count(); + uint32_t idx = *inout_index; + uint32_t cap = buf_len / (uint32_t)sizeof(struct vfs_dirent); + struct vfs_dirent* ents = (struct vfs_dirent*)buf; + uint32_t written = 0; + + while (written < cap) { + struct vfs_dirent e; + memset(&e, 0, sizeof(e)); + + if (idx == 0) { + e.d_ino = 5; e.d_type = FS_DIRECTORY; strcpy(e.d_name, "."); + } else if (idx == 1) { + e.d_ino = 1; e.d_type = FS_DIRECTORY; strcpy(e.d_name, ".."); + } else { + int pi = (int)(idx - 2); + if (pi >= count) break; + e.d_ino = PTY_SLAVE_INO_BASE + (uint32_t)pi; + e.d_type = FS_CHARDEVICE; + e.d_name[0] = '0' + (char)pi; + e.d_name[1] = '\0'; + } + + e.d_reclen = (uint16_t)sizeof(e); + ents[written] = e; + written++; + idx++; + } + + *inout_index = idx; + return (int)(written * (uint32_t)sizeof(struct vfs_dirent)); +} + void pty_init(void) { spinlock_init(&pty_lock); memset(g_ptys, 0, sizeof(g_ptys)); g_pty_count = 0; pty_init_pair(0); g_pty_count = 1; + + /* Register /dev/ptmx */ + memset(&g_dev_ptmx_node, 0, sizeof(g_dev_ptmx_node)); + strcpy(g_dev_ptmx_node.name, "ptmx"); + g_dev_ptmx_node.flags = FS_CHARDEVICE; + g_dev_ptmx_node.inode = PTY_MASTER_INO_BASE; + g_dev_ptmx_node.read = &pty_ptmx_read_fn; + g_dev_ptmx_node.write = &pty_ptmx_write_fn; + devfs_register_device(&g_dev_ptmx_node); + + /* Register /dev/pts directory */ + memset(&g_dev_pts_dir_node, 0, sizeof(g_dev_pts_dir_node)); + strcpy(g_dev_pts_dir_node.name, "pts"); + g_dev_pts_dir_node.flags = FS_DIRECTORY; + g_dev_pts_dir_node.inode = 5; + g_dev_pts_dir_node.finddir = &pty_pts_finddir; + g_dev_pts_dir_node.readdir = &pty_pts_readdir; + devfs_register_device(&g_dev_pts_dir_node); } int pty_alloc_pair(void) { diff --git a/src/kernel/tty.c b/src/kernel/tty.c index e7a4d1e..6a344f2 100644 --- a/src/kernel/tty.c +++ b/src/kernel/tty.c @@ -1,5 +1,6 @@ #include "tty.h" +#include "devfs.h" #include "keyboard.h" #include "process.h" #include "waitqueue.h" @@ -375,6 +376,25 @@ static void tty_keyboard_cb(char c) { tty_input_char(c); } +/* --- DevFS VFS-compatible wrappers --- */ + +static fs_node_t g_dev_console_node; +static fs_node_t g_dev_tty_node; + +static uint32_t tty_devfs_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) { + (void)node; (void)offset; + int rc = tty_read_kbuf(buffer, size); + if (rc < 0) return 0; + return (uint32_t)rc; +} + +static uint32_t tty_devfs_write(fs_node_t* node, uint32_t offset, uint32_t size, const uint8_t* buffer) { + (void)node; (void)offset; + int rc = tty_write_kbuf(buffer, size); + if (rc < 0) return 0; + return (uint32_t)rc; +} + void tty_init(void) { spinlock_init(&tty_lock); line_len = 0; @@ -384,6 +404,24 @@ void tty_init(void) { tty_fg_pgrp = 0; keyboard_set_callback(tty_keyboard_cb); + + /* Register /dev/console */ + memset(&g_dev_console_node, 0, sizeof(g_dev_console_node)); + strcpy(g_dev_console_node.name, "console"); + g_dev_console_node.flags = FS_CHARDEVICE; + g_dev_console_node.inode = 10; + g_dev_console_node.read = &tty_devfs_read; + g_dev_console_node.write = &tty_devfs_write; + devfs_register_device(&g_dev_console_node); + + /* Register /dev/tty */ + memset(&g_dev_tty_node, 0, sizeof(g_dev_tty_node)); + strcpy(g_dev_tty_node.name, "tty"); + g_dev_tty_node.flags = FS_CHARDEVICE; + g_dev_tty_node.inode = 3; + g_dev_tty_node.read = &tty_devfs_read; + g_dev_tty_node.write = &tty_devfs_write; + devfs_register_device(&g_dev_tty_node); } int tty_write(const void* user_buf, uint32_t len) {