yggdrasil/src/fs/devfs.rs

83 lines
2.2 KiB
Rust

//! Device virtual file system
use core::sync::atomic::{AtomicUsize, Ordering};
use abi::{
error::Error,
io::{FileAttr, FileMode, FileType, OpenOptions},
};
use alloc::{boxed::Box, format, string::String};
use kernel_util::util::OneTimeInit;
use vfs::{
CharDevice, CharDeviceWrapper, Vnode, VnodeImpl, VnodeKind, VnodeRef, DIR_POSITION_FROM_CACHE,
};
/// Describes the kind of a character device
#[derive(Debug)]
pub enum CharDeviceType {
/// Regular terminal
TtyRegular,
/// Serial terminal
TtySerial,
}
struct DevfsDirectory;
impl VnodeImpl for DevfsDirectory {
fn open(&self, _node: &VnodeRef, _opts: OpenOptions, _mode: FileMode) -> Result<u64, Error> {
Ok(DIR_POSITION_FROM_CACHE)
}
fn metadata(&self, _node: &VnodeRef) -> Result<FileAttr, Error> {
Ok(FileAttr {
size: 0,
mode: FileMode::default_dir(),
ty: FileType::Directory,
})
}
}
static DEVFS_ROOT: OneTimeInit<VnodeRef> = OneTimeInit::new();
/// Sets up the device filesystem
pub fn init() {
let node = Vnode::new("", VnodeKind::Directory);
node.set_data(Box::new(DevfsDirectory));
DEVFS_ROOT.init(node);
}
/// Returns the root of the devfs.
///
/// # Panics
///
/// Will panic if the devfs hasn't yet been initialized.
pub fn root() -> &'static VnodeRef {
DEVFS_ROOT.get()
}
fn _add_char_device(dev: &'static dyn CharDevice, name: String) -> Result<(), Error> {
infoln!("Add char device: {}", name);
let node = Vnode::new(name, VnodeKind::Char);
node.set_data(Box::new(CharDeviceWrapper::new(dev)));
DEVFS_ROOT.get().add_child(node);
Ok(())
}
/// Adds a character device to the devfs
pub fn add_char_device(dev: &'static dyn CharDevice, kind: CharDeviceType) -> Result<(), Error> {
static TTY_COUNT: AtomicUsize = AtomicUsize::new(0);
static TTYS_COUNT: AtomicUsize = AtomicUsize::new(0);
let (count, prefix) = match kind {
CharDeviceType::TtyRegular => (&TTY_COUNT, "tty"),
CharDeviceType::TtySerial => (&TTYS_COUNT, "ttyS"),
};
let value = count.fetch_add(1, Ordering::AcqRel);
let name = format!("{}{}", prefix, value);
_add_char_device(dev, name)
}