diff options
author | Ian Moffett <ian@osmora.org> | 2024-07-12 00:07:22 -0400 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2024-07-12 00:07:22 -0400 |
commit | d117265f1e2b465c29c919a7ad594232d645cf76 (patch) | |
tree | 2f758801628660f19783c5a3b31e3cbb2dec352a /sys/fs/devfs.c | |
parent | e93f80c60a900b747792cda7176c59521401821b (diff) |
kernel: Add support for devfs
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'sys/fs/devfs.c')
-rw-r--r-- | sys/fs/devfs.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/sys/fs/devfs.c b/sys/fs/devfs.c new file mode 100644 index 0000000..c1eb761 --- /dev/null +++ b/sys/fs/devfs.c @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2023-2024 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/vnode.h> +#include <sys/errno.h> +#include <sys/mount.h> +#include <sys/device.h> +#include <fs/devfs.h> +#include <vm/dynalloc.h> +#include <string.h> + +struct devfs_node { + const char *name; + uint8_t is_block : 1; + mode_t mode; + devmajor_t major; + dev_t dev; + TAILQ_ENTRY(devfs_node) link; +}; + +static TAILQ_HEAD(, devfs_node) devlist; + +static inline int +cdevsw_read(void *devsw, dev_t dev, struct sio_txn *sio) +{ + struct cdevsw *cdevsw = devsw; + + return cdevsw->read(dev, sio, 0); +} + +/* + * Get a devfs node by name. + * + * @name: Name to lookup. + */ +static struct devfs_node * +devfs_get_node(const char *name) +{ + struct devfs_node *dnp; + + TAILQ_FOREACH(dnp, &devlist, link) { + if (strcmp(dnp->name, name) == 0) { + return dnp; + } + } + + return NULL; +} + +static int +devfs_lookup(struct vop_lookup_args *args) +{ + int vtype, error; + const char *name = args->name; + struct devfs_node *dnp; + struct vnode *vp; + + if (*name == '/') + ++name; + + /* Make sure it isn't a path */ + for (const char *p = name; *p != '\0'; ++p) { + if (*p == '/') { + return -ENOENT; + } + } + + if ((dnp = devfs_get_node(name)) == NULL) + return -ENOENT; + + /* Now, create a vnode */ + vtype = (dnp->is_block) ? VBLK : VCHR; + if ((error = vfs_alloc_vnode(&vp, vtype)) != 0) + return error; + + vp->data = dnp; + vp->vops = &g_devfs_vops; + *args->vpp = vp; + return 0; +} + +static int +devfs_reclaim(struct vnode *vp) +{ + if (vp->data != NULL) + dynfree(vp->data); + + vp->data = NULL; + return 0; +} + +static int +devfs_read(struct vnode *vp, struct sio_txn *sio) +{ + struct devfs_node *dnp; + void *devsw; + + if ((dnp = vp->data) == NULL) + return -EIO; + + devsw = dev_get(dnp->major, dnp->dev); + + if (!dnp->is_block) + return cdevsw_read(devsw, dnp->dev, sio); + + /* TODO: Block devices */ + return -EIO; +} + +static int +devfs_init(struct fs_info *fip) +{ + struct vnode *vp; + struct mount *mp; + int error; + + /* Create a new vnode for devfs */ + if ((error = vfs_alloc_vnode(&vp, VDIR)) != 0) + return error; + + vp->vops = &g_devfs_vops; + TAILQ_INIT(&devlist); + mp = vfs_alloc_mount(vp, fip); + + vfs_name_mount(mp, "dev"); + TAILQ_INSERT_TAIL(&g_mountlist, mp, mnt_list); + return 0; +} + +/* + * Create an entry within devfs. + * + * @name: Device name. + * @major: Device major. + * @dev: Device minor. + * @mode: Permissions mask + */ +int +devfs_create_entry(const char *name, devmajor_t major, dev_t dev, mode_t mode) +{ + struct devfs_node *dnp; + + dnp = dynalloc(sizeof(*dnp)); + if (dnp == NULL) + return -ENOMEM; + + dnp->name = name; + dnp->major = major; + dnp->dev = dev; + dnp->mode = mode; + TAILQ_INSERT_TAIL(&devlist, dnp, link); + return 0; +} + +const struct vops g_devfs_vops = { + .lookup = devfs_lookup, + .reclaim = devfs_reclaim, + .read = devfs_read +}; + +const struct vfsops g_devfs_vfsops = { + .init = devfs_init +}; |