212 lines
4.5 KiB
C
212 lines
4.5 KiB
C
#include "user/errno.h"
|
|
#include "sys/block/blk.h"
|
|
#include "fs/devfs.h"
|
|
#include "fs/node.h"
|
|
#include "fs/vfs.h"
|
|
#include "sys/string.h"
|
|
#include "sys/assert.h"
|
|
#include "sys/string.h"
|
|
#include "fs/fs.h"
|
|
#include "sys/panic.h"
|
|
#include "sys/debug.h"
|
|
#include "sys/heap.h"
|
|
#include "sys/attr.h"
|
|
#include "sys/dev.h"
|
|
|
|
static struct vnode *devfs_root = NULL;
|
|
static int devfs_init(struct fs *fs, const char *opt);
|
|
static struct vnode *devfs_get_root(struct fs *fs);
|
|
static int devfs_vnode_stat(struct vnode *node, struct stat *st);
|
|
|
|
static char cdx_last = 'a';
|
|
static char sdx_last = 'a';
|
|
static char hdx_last = 'a';
|
|
static uint64_t dev_count = 0;
|
|
|
|
static struct fs_class _devfs = {
|
|
.name = "devfs",
|
|
.opt = 0,
|
|
.init = devfs_init,
|
|
.get_root = devfs_get_root
|
|
};
|
|
|
|
static struct vnode_operations _devfs_node_ops = {
|
|
.stat = devfs_vnode_stat
|
|
};
|
|
|
|
/////
|
|
|
|
static int dev_create_name(enum dev_class cls, int subcls, char *name) {
|
|
if (cls == DEV_CLASS_BLOCK) {
|
|
switch (subcls) {
|
|
case DEV_BLOCK_SDx:
|
|
strcpy(name, "sdx");
|
|
name[2] = sdx_last++;
|
|
return 0;
|
|
case DEV_BLOCK_CDx:
|
|
strcpy(name, "cdx");
|
|
name[2] = cdx_last++;
|
|
return 0;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static void devfs_ensure_root(void) {
|
|
// If root does not yet exist, make one
|
|
if (!devfs_root) {
|
|
devfs_root = vnode_create(VN_DIR, NULL);
|
|
devfs_root->flags |= VN_MEMORY;
|
|
devfs_root->mode = 0555;
|
|
devfs_root->uid = 0;
|
|
devfs_root->gid = 0;
|
|
devfs_root->op = &_devfs_node_ops;
|
|
}
|
|
}
|
|
|
|
/////
|
|
|
|
static int devfs_init(struct fs *fs, const char *opt) {
|
|
return 0;
|
|
}
|
|
|
|
static struct vnode *devfs_get_root(struct fs *fs) {
|
|
return devfs_root;
|
|
}
|
|
|
|
/////
|
|
|
|
int dev_add_live_link(const char *name, vnode_link_getter_t getter) {
|
|
struct vnode *node = vnode_create(VN_LNK, name);
|
|
node->target_func = getter;
|
|
node->flags |= VN_MEMORY | VN_PER_PROCESS;
|
|
|
|
devfs_ensure_root();
|
|
|
|
node->mode = 0777;
|
|
node->uid = 0;
|
|
node->gid = 0;
|
|
node->op = &_devfs_node_ops;
|
|
|
|
vnode_attach(devfs_root, node);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dev_add_link(const char *name, struct vnode *to) {
|
|
struct vnode *node = vnode_create(VN_LNK, name);
|
|
node->target = to;
|
|
node->flags |= VN_MEMORY;
|
|
|
|
devfs_ensure_root();
|
|
|
|
node->mode = 0777;
|
|
node->uid = 0;
|
|
node->gid = 0;
|
|
node->op = &_devfs_node_ops;
|
|
|
|
vnode_attach(devfs_root, node);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dev_add(enum dev_class cls, int subcls, void *dev, const char *name) {
|
|
char node_name[32];
|
|
struct vnode *node;
|
|
|
|
if (!name) {
|
|
if (dev_create_name(cls, subcls, node_name) != 0) {
|
|
return -1;
|
|
}
|
|
|
|
name = node_name;
|
|
}
|
|
|
|
// Create a filesystem node for the device
|
|
node = vnode_create(cls == DEV_CLASS_BLOCK ? VN_BLK : VN_CHR, name);
|
|
node->dev = dev;
|
|
|
|
// Use inode number to store full device class:subclass
|
|
node->ino = ((uint32_t) cls) | ((uint64_t) subcls << 32);
|
|
|
|
node->flags |= VN_MEMORY;
|
|
node->op = &_devfs_node_ops;
|
|
|
|
// Default permissions for devices
|
|
node->mode = 0600;
|
|
node->uid = 0;
|
|
node->gid = 0;
|
|
|
|
devfs_ensure_root();
|
|
|
|
// TODO: some devices are located in subdirs
|
|
vnode_attach(devfs_root, node);
|
|
|
|
kdebug("Created device node: %s\n", node->name);
|
|
|
|
if (cls == DEV_CLASS_BLOCK && subcls < DEV_BLOCK_PART) {
|
|
// Find partitions of block devices
|
|
blk_enumerate_partitions(dev, node);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dev_find(enum dev_class cls, const char *name, struct vnode **node) {
|
|
struct vnode *e;
|
|
int res;
|
|
|
|
_assert(node);
|
|
|
|
if (!devfs_root) {
|
|
return -ENODEV;
|
|
}
|
|
|
|
if ((res = vnode_lookup_child(devfs_root, name, &e)) != 0) {
|
|
return res;
|
|
}
|
|
|
|
if (e->type == VN_LNK) {
|
|
_assert(e->target);
|
|
e = e->target;
|
|
}
|
|
|
|
if (cls == DEV_CLASS_BLOCK && e->type != VN_BLK) {
|
|
return -ENODEV;
|
|
}
|
|
if (cls == DEV_CLASS_CHAR && e->type != VN_CHR) {
|
|
return -ENODEV;
|
|
}
|
|
|
|
*node = e;
|
|
|
|
return 0;
|
|
}
|
|
|
|
////
|
|
|
|
static int devfs_vnode_stat(struct vnode *node, struct stat *st) {
|
|
st->st_mode = (node->mode & VFS_MODE_MASK) | vfs_vnode_to_mode(node->type);
|
|
st->st_uid = node->uid;
|
|
st->st_gid = node->gid;
|
|
st->st_size = 0;
|
|
st->st_blksize = 0;
|
|
st->st_blocks = 0;
|
|
st->st_ino = 0;
|
|
|
|
st->st_atime = system_boot_time;
|
|
st->st_mtime = system_boot_time;
|
|
st->st_ctime = system_boot_time;
|
|
|
|
st->st_dev = 0;
|
|
st->st_rdev = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
////
|
|
|
|
__init(devfs_class_init) {
|
|
fs_class_register(&_devfs);
|
|
}
|