use alloc::sync::Arc;
use core::{any::Any, task::Context};
use ax_fs::CachedFile;
use ax_memory_addr::PhysAddrRange;
use axfs_ng_vfs::{
DeviceId, FileNodeOps, FilesystemOps, Metadata, MetadataUpdate, NodeFlags, NodeOps,
NodePermission, NodeType, VfsError, VfsResult,
};
use axpoll::{IoEvents, Pollable};
use inherit_methods_macro::inherit_methods;
use super::{SimpleFs, SimpleFsNode};
#[cfg(feature = "kcov")]
use crate::mm::SharedPages;
#[derive(Clone)]
pub enum DeviceMmap {
None,
Physical(PhysAddrRange),
Cache(CachedFile),
#[cfg(feature = "kcov")]
NotConfigured,
#[cfg(feature = "kcov")]
SharedPages(Arc<SharedPages>),
}
pub trait DeviceOps: Send + Sync {
fn read_at(&self, buf: &mut [u8], offset: u64) -> VfsResult<usize>;
fn write_at(&self, buf: &[u8], offset: u64) -> VfsResult<usize>;
fn ioctl(&self, _cmd: u32, _arg: usize) -> VfsResult<usize> {
Err(VfsError::NotATty)
}
fn as_any(&self) -> &dyn Any;
fn as_pollable(&self) -> Option<&dyn Pollable> {
None
}
fn mmap(&self, _offset: u64, _length: u64) -> DeviceMmap {
DeviceMmap::None
}
fn flags(&self) -> NodeFlags {
NodeFlags::empty()
}
fn open(&self, _exclusive: bool) -> VfsResult<()> {
Ok(())
}
fn close(&self, _exclusive: bool) {}
}
pub struct Device {
node: SimpleFsNode,
ops: Arc<dyn DeviceOps>,
}
impl Device {
pub fn new(
fs: Arc<SimpleFs>,
node_type: NodeType,
device_id: DeviceId,
ops: Arc<dyn DeviceOps>,
) -> Arc<Self> {
let node = SimpleFsNode::new(fs, node_type, NodePermission::default());
node.metadata.lock().rdev = device_id;
Arc::new(Self { node, ops })
}
pub fn inner(&self) -> &Arc<dyn DeviceOps> {
&self.ops
}
pub fn set_device_id(&self, device_id: DeviceId) {
self.node.metadata.lock().rdev = device_id;
}
pub fn mmap(&self, offset: u64, length: u64) -> DeviceMmap {
self.ops.mmap(offset, length)
}
}
#[inherit_methods(from = "self.node")]
impl NodeOps for Device {
fn inode(&self) -> u64;
fn metadata(&self) -> VfsResult<Metadata>;
fn update_metadata(&self, update: MetadataUpdate) -> VfsResult<()>;
fn filesystem(&self) -> &dyn FilesystemOps;
fn sync(&self, _data_only: bool) -> VfsResult<()> {
Err(VfsError::InvalidInput)
}
fn into_any(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
self
}
fn len(&self) -> VfsResult<u64> {
Ok(0)
}
fn flags(&self) -> NodeFlags {
self.ops.flags()
}
}
impl FileNodeOps for Device {
fn read_at(&self, buf: &mut [u8], offset: u64) -> VfsResult<usize> {
self.ops.read_at(buf, offset)
}
fn write_at(&self, buf: &[u8], offset: u64) -> VfsResult<usize> {
self.ops.write_at(buf, offset)
}
fn append(&self, _buf: &[u8]) -> VfsResult<(usize, u64)> {
Err(VfsError::NotATty)
}
fn set_len(&self, _len: u64) -> VfsResult<()> {
if self.write_at(b"", 0).is_ok() {
Ok(())
} else {
Err(VfsError::BadFileDescriptor)
}
}
fn set_symlink(&self, _target: &str) -> VfsResult<()> {
Err(VfsError::BadFileDescriptor)
}
fn ioctl(&self, cmd: u32, arg: usize) -> VfsResult<usize> {
self.ops.ioctl(cmd, arg)
}
}
impl Pollable for Device {
fn poll(&self) -> IoEvents {
if let Some(pollable) = self.ops.as_pollable() {
pollable.poll()
} else {
IoEvents::IN | IoEvents::OUT
}
}
fn register(&self, context: &mut Context<'_>, events: IoEvents) {
if let Some(pollable) = self.ops.as_pollable() {
pollable.register(context, events);
}
}
}