mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 19:36:47 +00:00
完善设备驱动模型&调试串口驱动 (#379)
* 完成了基本架构重构,正在进行兼容 * 重构了所有 Device Driver ,还没有接上具体设备 * 基本把 Uart 接上了,还没有测试 * 初步完成系统设备初始化 * 初步重构 BlockDevice ,使其兼容新的 Device 结构 * 修改文件系统内的部分函数调用以满足重构后的接口 * 测试完 Uart 设备的功能 * 移除了自动添加的文件 * 修复了 warning 和部分格式 * 解决warning,并且修正sysfs初始化的位置 * Patch fix * 删除了 sysinfo 的默认实现 * 删除了字符设备读写的 offset 参数 * 修复了 warning 和一些小逻辑错误 --------- Co-authored-by: longjin <longjin@RinGoTek.cn>
This commit is contained in:
parent
9029414af2
commit
b087521e07
@ -5,7 +5,7 @@ use hashbrown::HashSet;
|
|||||||
use x86::time::rdtsc;
|
use x86::time::rdtsc;
|
||||||
use x86_64::registers::model_specific::EferFlags;
|
use x86_64::registers::model_specific::EferFlags;
|
||||||
|
|
||||||
use crate::driver::uart::uart::c_uart_send_str;
|
use crate::driver::uart::uart_device::c_uart_send_str;
|
||||||
use crate::include::bindings::bindings::{
|
use crate::include::bindings::bindings::{
|
||||||
multiboot2_get_memory, multiboot2_iter, multiboot_mmap_entry_t,
|
multiboot2_get_memory, multiboot2_iter, multiboot_mmap_entry_t,
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/// 引入Module
|
/// 引入Module
|
||||||
use crate::syscall::SystemError;
|
use crate::{driver::base::device::Device, syscall::SystemError};
|
||||||
use alloc::{sync::Arc, vec::Vec};
|
use alloc::{sync::Arc, vec::Vec};
|
||||||
use core::{any::Any, fmt::Debug};
|
use core::any::Any;
|
||||||
|
|
||||||
use super::disk_info::Partition;
|
use super::disk_info::Partition;
|
||||||
|
|
||||||
@ -17,172 +17,10 @@ use super::disk_info::Partition;
|
|||||||
pub type BlockId = usize;
|
pub type BlockId = usize;
|
||||||
|
|
||||||
/// 定义常量
|
/// 定义常量
|
||||||
const BLK_SIZE_LOG2_LIMIT: u8 = 12; // 设定块设备的块大小不能超过 1 << 12.
|
pub const BLK_SIZE_LOG2_LIMIT: u8 = 12; // 设定块设备的块大小不能超过 1 << 12.
|
||||||
/// 在DragonOS中,我们认为磁盘的每个LBA大小均为512字节。(注意,文件系统的1个扇区可能事实上是多个LBA)
|
/// 在DragonOS中,我们认为磁盘的每个LBA大小均为512字节。(注意,文件系统的1个扇区可能事实上是多个LBA)
|
||||||
pub const LBA_SIZE: usize = 512;
|
pub const LBA_SIZE: usize = 512;
|
||||||
|
|
||||||
/// @brief 设备应该实现的操作
|
|
||||||
/// @usage Device::read_at()
|
|
||||||
pub trait Device: Any + Send + Sync + Debug {
|
|
||||||
/// Notice buffer对应设备按字节划分,使用u8类型
|
|
||||||
/// Notice offset应该从0开始计数
|
|
||||||
|
|
||||||
/// @brief: 从设备的第offset个字节开始,读取len个byte,存放到buf中
|
|
||||||
/// @parameter offset: 起始字节偏移量
|
|
||||||
/// @parameter len: 读取字节的数量
|
|
||||||
/// @parameter buf: 目标数组
|
|
||||||
/// @return: 如果操作成功,返回操作的长度(单位是字节);否则返回错误码;如果操作异常,但是并没有检查出什么错误,将返回已操作的长度
|
|
||||||
fn read_at(&self, offset: usize, len: usize, buf: &mut [u8]) -> Result<usize, SystemError>;
|
|
||||||
|
|
||||||
/// @brief: 从设备的第offset个字节开始,把buf数组的len个byte,写入到设备中
|
|
||||||
/// @parameter offset: 起始字节偏移量
|
|
||||||
/// @parameter len: 读取字节的数量
|
|
||||||
/// @parameter buf: 目标数组
|
|
||||||
/// @return: 如果操作成功,返回操作的长度(单位是字节);否则返回错误码;如果操作异常,但是并没有检查出什么错误,将返回已操作的长度
|
|
||||||
fn write_at(&self, offset: usize, len: usize, buf: &[u8]) -> Result<usize, SystemError>;
|
|
||||||
|
|
||||||
/// @brief: 同步信息,把所有的dirty数据写回设备 - 待实现
|
|
||||||
fn sync(&self) -> Result<(), SystemError>;
|
|
||||||
|
|
||||||
// TODO: 待实现 open, close
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief 块设备应该实现的操作
|
|
||||||
pub trait BlockDevice: Any + Send + Sync + Debug {
|
|
||||||
/// @brief: 在块设备中,从第lba_id_start个块开始,读取count个块数据,存放到buf中
|
|
||||||
///
|
|
||||||
/// @parameter lba_id_start: 起始块
|
|
||||||
/// @parameter count: 读取块的数量
|
|
||||||
/// @parameter buf: 目标数组
|
|
||||||
/// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节;
|
|
||||||
/// 否则返回Err(错误码),其中错误码为负数;
|
|
||||||
/// 如果操作异常,但是并没有检查出什么错误,将返回Err(已操作的长度)
|
|
||||||
fn read_at(
|
|
||||||
&self,
|
|
||||||
lba_id_start: BlockId,
|
|
||||||
count: usize,
|
|
||||||
buf: &mut [u8],
|
|
||||||
) -> Result<usize, SystemError>;
|
|
||||||
|
|
||||||
/// @brief: 在块设备中,从第lba_id_start个块开始,把buf中的count个块数据,存放到设备中
|
|
||||||
/// @parameter lba_id_start: 起始块
|
|
||||||
/// @parameter count: 写入块的数量
|
|
||||||
/// @parameter buf: 目标数组
|
|
||||||
/// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节;
|
|
||||||
/// 否则返回Err(错误码),其中错误码为负数;
|
|
||||||
/// 如果操作异常,但是并没有检查出什么错误,将返回Err(已操作的长度)
|
|
||||||
fn write_at(
|
|
||||||
&self,
|
|
||||||
lba_id_start: BlockId,
|
|
||||||
count: usize,
|
|
||||||
buf: &[u8],
|
|
||||||
) -> Result<usize, SystemError>;
|
|
||||||
|
|
||||||
/// @brief: 同步磁盘信息,把所有的dirty数据写回硬盘 - 待实现
|
|
||||||
fn sync(&self) -> Result<(), SystemError>;
|
|
||||||
|
|
||||||
/// @brief: 每个块设备都必须固定自己块大小,而且该块大小必须是2的幂次
|
|
||||||
/// @return: 返回一个固定量,硬编码(编程的时候固定的常量).
|
|
||||||
fn blk_size_log2(&self) -> u8;
|
|
||||||
|
|
||||||
// TODO: 待实现 open, close
|
|
||||||
|
|
||||||
/// @brief 本函数用于实现动态转换。
|
|
||||||
/// 具体的文件系统在实现本函数时,最简单的方式就是:直接返回self
|
|
||||||
fn as_any_ref(&self) -> &dyn Any;
|
|
||||||
|
|
||||||
/// @brief 本函数用于将BlockDevice转换为Device。
|
|
||||||
/// 由于实现了BlockDevice的结构体,本身也实现了Device Trait, 因此转换是可能的。
|
|
||||||
/// 思路:在BlockDevice的结构体中新增一个self_ref变量,返回self_ref.upgrade()即可。
|
|
||||||
fn device(&self) -> Arc<dyn Device>;
|
|
||||||
|
|
||||||
/// @brief 返回块设备的块大小(单位:字节)
|
|
||||||
fn block_size(&self) -> usize;
|
|
||||||
|
|
||||||
/// @brief 返回当前磁盘上的所有分区的Arc指针数组
|
|
||||||
fn partitions(&self) -> Vec<Arc<Partition>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 对于所有<块设备>自动实现 Device Trait 的 read_at 和 write_at 函数
|
|
||||||
impl<T: BlockDevice> Device for T {
|
|
||||||
// 读取设备操作,读取设备内部 [offset, offset + buf.len) 区间内的字符,存放到 buf 中
|
|
||||||
fn read_at(&self, offset: usize, len: usize, buf: &mut [u8]) -> Result<usize, SystemError> {
|
|
||||||
if len > buf.len() {
|
|
||||||
return Err(SystemError::E2BIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
let iter = BlockIter::new_multiblock(offset, offset + len, self.blk_size_log2());
|
|
||||||
let multi = iter.multiblock;
|
|
||||||
|
|
||||||
// 枚举每一个range
|
|
||||||
for range in iter {
|
|
||||||
let buf_begin = range.origin_begin() - offset; // 本次读操作的起始位置/已经读了这么多字节
|
|
||||||
let buf_end = range.origin_end() - offset;
|
|
||||||
let buf_slice = &mut buf[buf_begin..buf_end];
|
|
||||||
let count: usize = (range.lba_end - range.lba_start).try_into().unwrap();
|
|
||||||
let full = multi && range.is_multi() || !multi && range.is_full();
|
|
||||||
|
|
||||||
if full {
|
|
||||||
// 调用 BlockDevice::read_at() 直接把引用传进去,不是把整个数组move进去
|
|
||||||
BlockDevice::read_at(self, range.lba_start, count, buf_slice)?;
|
|
||||||
} else {
|
|
||||||
// 判断块的长度不能超过最大值
|
|
||||||
if self.blk_size_log2() > BLK_SIZE_LOG2_LIMIT {
|
|
||||||
return Err(SystemError::E2BIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut temp = Vec::new();
|
|
||||||
temp.resize(1usize << self.blk_size_log2(), 0);
|
|
||||||
BlockDevice::read_at(self, range.lba_start, 1, &mut temp[..])?;
|
|
||||||
// 把数据从临时buffer复制到目标buffer
|
|
||||||
buf_slice.copy_from_slice(&temp[range.begin..range.end]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ok(len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 写入设备操作,把 buf 的数据写入到设备内部 [offset, offset + len) 区间内
|
|
||||||
fn write_at(&self, offset: usize, len: usize, buf: &[u8]) -> Result<usize, SystemError> {
|
|
||||||
// assert!(len <= buf.len());
|
|
||||||
if len > buf.len() {
|
|
||||||
return Err(SystemError::E2BIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
let iter = BlockIter::new_multiblock(offset, offset + len, self.blk_size_log2());
|
|
||||||
let multi = iter.multiblock;
|
|
||||||
|
|
||||||
for range in iter {
|
|
||||||
let buf_begin = range.origin_begin() - offset; // 本次读操作的起始位置/已经读了这么多字节
|
|
||||||
let buf_end = range.origin_end() - offset;
|
|
||||||
let buf_slice = &buf[buf_begin..buf_end];
|
|
||||||
let count: usize = (range.lba_end - range.lba_start).try_into().unwrap();
|
|
||||||
let full = multi && range.is_multi() || !multi && range.is_full();
|
|
||||||
|
|
||||||
if full {
|
|
||||||
BlockDevice::write_at(self, range.lba_start, count, buf_slice)?;
|
|
||||||
} else {
|
|
||||||
if self.blk_size_log2() > BLK_SIZE_LOG2_LIMIT {
|
|
||||||
return Err(SystemError::E2BIG);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut temp = Vec::new();
|
|
||||||
temp.resize(1usize << self.blk_size_log2(), 0);
|
|
||||||
// 由于块设备每次读写都是整块的,在不完整写入之前,必须把不完整的地方补全
|
|
||||||
BlockDevice::read_at(self, range.lba_start, 1, &mut temp[..])?;
|
|
||||||
// 把数据从临时buffer复制到目标buffer
|
|
||||||
temp[range.begin..range.end].copy_from_slice(&buf_slice);
|
|
||||||
BlockDevice::write_at(self, range.lba_start, 1, &temp[..])?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Ok(len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 数据同步
|
|
||||||
fn sync(&self) -> Result<(), SystemError> {
|
|
||||||
BlockDevice::sync(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief 块设备的迭代器
|
/// @brief 块设备的迭代器
|
||||||
/// @usage 某次操作读/写块设备的[L,R]范围内的字节,
|
/// @usage 某次操作读/写块设备的[L,R]范围内的字节,
|
||||||
/// 那么可以使用此结构体进行迭代遍历,每次调用next()返回一个BlockRange
|
/// 那么可以使用此结构体进行迭代遍历,每次调用next()返回一个BlockRange
|
||||||
@ -331,3 +169,141 @@ pub fn __bytes_to_lba(addr: usize, blk_size: usize) -> BlockId {
|
|||||||
pub fn __lba_to_bytes(lba_id: usize, blk_size: usize) -> BlockId {
|
pub fn __lba_to_bytes(lba_id: usize, blk_size: usize) -> BlockId {
|
||||||
return lba_id * blk_size;
|
return lba_id * blk_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief 块设备应该实现的操作
|
||||||
|
pub trait BlockDevice: Device {
|
||||||
|
/// @brief: 在块设备中,从第lba_id_start个块开始,读取count个块数据,存放到buf中
|
||||||
|
///
|
||||||
|
/// @parameter lba_id_start: 起始块
|
||||||
|
/// @parameter count: 读取块的数量
|
||||||
|
/// @parameter buf: 目标数组
|
||||||
|
/// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节;
|
||||||
|
/// 否则返回Err(错误码),其中错误码为负数;
|
||||||
|
/// 如果操作异常,但是并没有检查出什么错误,将返回Err(已操作的长度)
|
||||||
|
fn read_at(
|
||||||
|
&self,
|
||||||
|
lba_id_start: BlockId,
|
||||||
|
count: usize,
|
||||||
|
buf: &mut [u8],
|
||||||
|
) -> Result<usize, SystemError>;
|
||||||
|
|
||||||
|
/// @brief: 在块设备中,从第lba_id_start个块开始,把buf中的count个块数据,存放到设备中
|
||||||
|
/// @parameter lba_id_start: 起始块
|
||||||
|
/// @parameter count: 写入块的数量
|
||||||
|
/// @parameter buf: 目标数组
|
||||||
|
/// @return: 如果操作成功,返回 Ok(操作的长度) 其中单位是字节;
|
||||||
|
/// 否则返回Err(错误码),其中错误码为负数;
|
||||||
|
/// 如果操作异常,但是并没有检查出什么错误,将返回Err(已操作的长度)
|
||||||
|
fn write_at(
|
||||||
|
&self,
|
||||||
|
lba_id_start: BlockId,
|
||||||
|
count: usize,
|
||||||
|
buf: &[u8],
|
||||||
|
) -> Result<usize, SystemError>;
|
||||||
|
|
||||||
|
/// @brief: 同步磁盘信息,把所有的dirty数据写回硬盘 - 待实现
|
||||||
|
fn sync(&self) -> Result<(), SystemError>;
|
||||||
|
|
||||||
|
/// @brief: 每个块设备都必须固定自己块大小,而且该块大小必须是2的幂次
|
||||||
|
/// @return: 返回一个固定量,硬编码(编程的时候固定的常量).
|
||||||
|
fn blk_size_log2(&self) -> u8;
|
||||||
|
|
||||||
|
// TODO: 待实现 open, close
|
||||||
|
|
||||||
|
/// @brief 本函数用于实现动态转换。
|
||||||
|
/// 具体的文件系统在实现本函数时,最简单的方式就是:直接返回self
|
||||||
|
fn as_any_ref(&self) -> &dyn Any;
|
||||||
|
|
||||||
|
/// @brief 本函数用于将BlockDevice转换为Device。
|
||||||
|
/// 由于实现了BlockDevice的结构体,本身也实现了Device Trait, 因此转换是可能的。
|
||||||
|
/// 思路:在BlockDevice的结构体中新增一个self_ref变量,返回self_ref.upgrade()即可。
|
||||||
|
fn device(&self) -> Arc<dyn Device>;
|
||||||
|
|
||||||
|
/// @brief 返回块设备的块大小(单位:字节)
|
||||||
|
fn block_size(&self) -> usize;
|
||||||
|
|
||||||
|
/// @brief 返回当前磁盘上的所有分区的Arc指针数组
|
||||||
|
fn partitions(&self) -> Vec<Arc<Partition>>;
|
||||||
|
|
||||||
|
fn write_at_bytes(&self, offset: usize, len: usize, buf: &[u8]) -> Result<usize, SystemError> {
|
||||||
|
// assert!(len <= buf.len());
|
||||||
|
if len > buf.len() {
|
||||||
|
return Err(SystemError::E2BIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
let iter = BlockIter::new_multiblock(offset, offset + len, self.blk_size_log2());
|
||||||
|
let multi = iter.multiblock;
|
||||||
|
|
||||||
|
for range in iter {
|
||||||
|
let buf_begin = range.origin_begin() - offset; // 本次读操作的起始位置/已经读了这么多字节
|
||||||
|
let buf_end = range.origin_end() - offset;
|
||||||
|
let buf_slice = &buf[buf_begin..buf_end];
|
||||||
|
let count: usize = (range.lba_end - range.lba_start).try_into().unwrap();
|
||||||
|
let full = multi && range.is_multi() || !multi && range.is_full();
|
||||||
|
|
||||||
|
if full {
|
||||||
|
self.write_at(range.lba_start, count, buf_slice)?;
|
||||||
|
} else {
|
||||||
|
if self.blk_size_log2() > BLK_SIZE_LOG2_LIMIT {
|
||||||
|
return Err(SystemError::E2BIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut temp = Vec::new();
|
||||||
|
temp.resize(1usize << self.blk_size_log2(), 0);
|
||||||
|
// 由于块设备每次读写都是整块的,在不完整写入之前,必须把不完整的地方补全
|
||||||
|
self.write_at(range.lba_start, 1, &mut temp[..])?;
|
||||||
|
// 把数据从临时buffer复制到目标buffer
|
||||||
|
temp[range.begin..range.end].copy_from_slice(&buf_slice);
|
||||||
|
self.write_at(range.lba_start, 1, &temp[..])?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(len);
|
||||||
|
//self.0.lock().write_at(lba_id_start, count, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_at_bytes(
|
||||||
|
&self,
|
||||||
|
offset: usize,
|
||||||
|
len: usize,
|
||||||
|
buf: &mut [u8],
|
||||||
|
) -> Result<usize, SystemError> {
|
||||||
|
if len > buf.len() {
|
||||||
|
return Err(SystemError::E2BIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
let iter = BlockIter::new_multiblock(offset, offset + len, self.blk_size_log2());
|
||||||
|
let multi = iter.multiblock;
|
||||||
|
|
||||||
|
// 枚举每一个range
|
||||||
|
for range in iter {
|
||||||
|
let buf_begin = range.origin_begin() - offset; // 本次读操作的起始位置/已经读了这么多字节
|
||||||
|
let buf_end = range.origin_end() - offset;
|
||||||
|
let buf_slice = &mut buf[buf_begin..buf_end];
|
||||||
|
let count: usize = (range.lba_end - range.lba_start).try_into().unwrap();
|
||||||
|
let full = multi && range.is_multi() || !multi && range.is_full();
|
||||||
|
|
||||||
|
if full {
|
||||||
|
// 调用 BlockDevice::read_at() 直接把引用传进去,不是把整个数组move进去
|
||||||
|
self.read_at(range.lba_start, count, buf)?;
|
||||||
|
} else {
|
||||||
|
// 判断块的长度不能超过最大值
|
||||||
|
if self.blk_size_log2() > BLK_SIZE_LOG2_LIMIT {
|
||||||
|
return Err(SystemError::E2BIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut temp = Vec::new();
|
||||||
|
temp.resize(1usize << self.blk_size_log2(), 0);
|
||||||
|
self.read_at(range.lba_start, 1, &mut temp[..])?;
|
||||||
|
|
||||||
|
// 把数据从临时buffer复制到目标buffer
|
||||||
|
buf_slice.copy_from_slice(&temp[range.begin..range.end]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(len);
|
||||||
|
|
||||||
|
// kdebug!(
|
||||||
|
// "ahci read at {lba_id_start}, count={count}, lock={:?}",
|
||||||
|
// self.0
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
use super::device::BlockDevice;
|
|
||||||
|
|
||||||
use alloc::sync::{Arc, Weak};
|
use alloc::sync::{Arc, Weak};
|
||||||
|
|
||||||
|
use super::block_device::BlockDevice;
|
||||||
|
|
||||||
pub type SectorT = u64;
|
pub type SectorT = u64;
|
||||||
|
|
||||||
pub const BLK_TYPE_AHCI: u64 = 0;
|
pub const BLK_TYPE_AHCI: u64 = 0;
|
@ -1,5 +1,4 @@
|
|||||||
pub mod block;
|
pub mod block_device;
|
||||||
pub mod device;
|
|
||||||
pub mod disk_info;
|
pub mod disk_info;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
@ -1,285 +1,25 @@
|
|||||||
use super::{
|
use crate::syscall::SystemError;
|
||||||
device::{mkdev, DeviceNumber, KObject},
|
|
||||||
map::{kobj_map, kobj_unmap, LockedKObjMap},
|
|
||||||
};
|
|
||||||
use crate::{filesystem::vfs::IndexNode, kerror, libs::spinlock::SpinLock, syscall::SystemError};
|
|
||||||
use alloc::{sync::Arc, vec::Vec};
|
|
||||||
use core::cmp::Ordering;
|
|
||||||
|
|
||||||
const CHARDEV_MAJOR_HASH_SIZE: usize = 255;
|
use super::device::Device;
|
||||||
const CHARDEV_MAJOR_MAX: usize = 512;
|
|
||||||
const MINOR_BITS: usize = 20;
|
|
||||||
const MINOR_MASK: usize = 1 << MINOR_BITS - 1;
|
|
||||||
/* Marks the bottom of the first segment of free char majors */
|
|
||||||
const CHARDEV_MAJOR_DYN_END: usize = 234;
|
|
||||||
/* Marks the top and bottom of the second segment of free char majors */
|
|
||||||
const CHARDEV_MAJOR_DYN_EXT_START: usize = 511;
|
|
||||||
const CHARDEV_MAJOR_DYN_EXT_END: usize = 384;
|
|
||||||
|
|
||||||
lazy_static! {
|
pub trait CharDevice: Device {
|
||||||
// 全局字符设备号管理实例
|
/// Notice buffer对应设备按字节划分,使用u8类型
|
||||||
pub static ref CHARDEVS: Arc<LockedChrDevs> = Arc::new(LockedChrDevs::default());
|
/// Notice offset应该从0开始计数
|
||||||
|
|
||||||
// 全局字符设备管理实例
|
/// @brief: 从设备的第offset个字节开始,读取len个byte,存放到buf中
|
||||||
pub static ref CDEVMAP: Arc<LockedKObjMap> = Arc::new(LockedKObjMap::default());
|
/// @parameter offset: 起始字节偏移量
|
||||||
}
|
/// @parameter len: 读取字节的数量
|
||||||
|
/// @parameter buf: 目标数组
|
||||||
pub trait CharDevice: KObject {
|
/// @return: 如果操作成功,返回操作的长度(单位是字节);否则返回错误码;如果操作异常,但是并没有检查出什么错误,将返回已操作的长度
|
||||||
/// @brief: 打开设备
|
fn read(&self, len: usize, buf: &mut [u8]) -> Result<usize, SystemError>;
|
||||||
/// @parameter: file: devfs inode
|
|
||||||
/// @return: 打开成功,返回OK(()),失败,返回错误代码
|
/// @brief: 从设备的第offset个字节开始,把buf数组的len个byte,写入到设备中
|
||||||
fn open(&self, file: Arc<dyn IndexNode>) -> Result<(), SystemError>;
|
/// @parameter offset: 起始字节偏移量
|
||||||
|
/// @parameter len: 读取字节的数量
|
||||||
/// @brief: 关闭设备
|
/// @parameter buf: 目标数组
|
||||||
/// @parameter: file: devfs inode
|
/// @return: 如果操作成功,返回操作的长度(单位是字节);否则返回错误码;如果操作异常,但是并没有检查出什么错误,将返回已操作的长度
|
||||||
/// @return: 关闭成功,返回OK(()),失败,返回错误代码
|
fn write(&self, len: usize, buf: &[u8]) -> Result<usize, SystemError>;
|
||||||
fn close(&self, file: Arc<dyn IndexNode>) -> Result<(), SystemError>;
|
|
||||||
}
|
/// @brief: 同步信息,把所有的dirty数据写回设备 - 待实现
|
||||||
|
fn sync(&self) -> Result<(), SystemError>;
|
||||||
// 管理字符设备号的map(加锁)
|
|
||||||
pub struct LockedChrDevs(SpinLock<ChrDevs>);
|
|
||||||
|
|
||||||
impl Default for LockedChrDevs {
|
|
||||||
fn default() -> Self {
|
|
||||||
LockedChrDevs(SpinLock::new(ChrDevs::default()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 管理字符设备号的map
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct ChrDevs(Vec<Vec<CharDeviceStruct>>);
|
|
||||||
|
|
||||||
impl Default for ChrDevs {
|
|
||||||
fn default() -> Self {
|
|
||||||
ChrDevs(vec![Vec::new(); CHARDEV_MAJOR_HASH_SIZE])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 字符设备在系统中的实例,devfs通过该结构与实际字符设备进行联系
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct CharDeviceStruct {
|
|
||||||
dev_t: DeviceNumber, //起始设备号
|
|
||||||
minorct: usize, // 次设备号数量
|
|
||||||
name: &'static str, //字符设备名
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CharDeviceStruct {
|
|
||||||
/// @brief: 创建实例
|
|
||||||
/// @parameter: dev_t: 设备号
|
|
||||||
/// minorct: 次设备号数量
|
|
||||||
/// name: 字符设备名
|
|
||||||
/// char: 字符设备实例
|
|
||||||
/// @return: 实例
|
|
||||||
///
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn new(dev_t: DeviceNumber, minorct: usize, name: &'static str) -> Self {
|
|
||||||
Self {
|
|
||||||
dev_t,
|
|
||||||
minorct,
|
|
||||||
name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief: 获取起始次设备号
|
|
||||||
/// @parameter: None
|
|
||||||
/// @return: 起始设备号
|
|
||||||
///
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn device_number(&self) -> DeviceNumber {
|
|
||||||
self.dev_t
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief: 获取起始次设备号
|
|
||||||
/// @parameter: None
|
|
||||||
/// @return: 起始设备号
|
|
||||||
///
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn base_minor(&self) -> usize {
|
|
||||||
self.dev_t.minor()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief: 获取次设备号数量
|
|
||||||
/// @parameter: None
|
|
||||||
/// @return: 次设备号数量
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn minorct(&self) -> usize {
|
|
||||||
self.minorct
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief 字符设备框架函数集
|
|
||||||
pub struct CharDevOps;
|
|
||||||
|
|
||||||
impl CharDevOps {
|
|
||||||
/// @brief: 主设备号转下标
|
|
||||||
/// @parameter: major: 主设备号
|
|
||||||
/// @return: 返回下标
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn major_to_index(major: usize) -> usize {
|
|
||||||
return major % CHARDEV_MAJOR_HASH_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief: 动态获取主设备号
|
|
||||||
/// @parameter: None
|
|
||||||
/// @return: 如果成功,返回主设备号,否则,返回错误码
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn find_dynamic_major() -> Result<usize, SystemError> {
|
|
||||||
let chardevs = CHARDEVS.0.lock();
|
|
||||||
// 寻找主设备号为234~255的设备
|
|
||||||
for index in (CHARDEV_MAJOR_DYN_END..CHARDEV_MAJOR_HASH_SIZE).rev() {
|
|
||||||
if let Some(item) = chardevs.0.get(index) {
|
|
||||||
if item.is_empty() {
|
|
||||||
return Ok(index); // 返回可用的主设备号
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 寻找主设备号在384~511的设备
|
|
||||||
for index in (CHARDEV_MAJOR_DYN_EXT_END + 1..CHARDEV_MAJOR_DYN_EXT_START + 1).rev() {
|
|
||||||
if let Some(chardevss) = chardevs.0.get(Self::major_to_index(index)) {
|
|
||||||
let mut flag = true;
|
|
||||||
for item in chardevss {
|
|
||||||
if item.device_number().major() == index {
|
|
||||||
flag = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if flag {
|
|
||||||
// 如果数组中不存在主设备号等于index的设备
|
|
||||||
return Ok(index); // 返回可用的主设备号
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Err(SystemError::EBUSY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief: 注册设备号,该函数需要指定主设备号
|
|
||||||
/// @parameter: from: 主设备号
|
|
||||||
/// count: 次设备号数量
|
|
||||||
/// name: 字符设备名
|
|
||||||
/// @return: 如果注册成功,返回设备号,否则,返回错误码
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn register_chardev_region(
|
|
||||||
from: DeviceNumber,
|
|
||||||
count: usize,
|
|
||||||
name: &'static str,
|
|
||||||
) -> Result<DeviceNumber, SystemError> {
|
|
||||||
Self::__register_chardev_region(from, count, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief: 注册设备号,该函数自动分配主设备号
|
|
||||||
/// @parameter: baseminor: 主设备号
|
|
||||||
/// count: 次设备号数量
|
|
||||||
/// name: 字符设备名
|
|
||||||
/// @return: 如果注册成功,返回,否则,返回false
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn alloc_chardev_region(
|
|
||||||
baseminor: usize,
|
|
||||||
count: usize,
|
|
||||||
name: &'static str,
|
|
||||||
) -> Result<DeviceNumber, SystemError> {
|
|
||||||
Self::__register_chardev_region(mkdev(0, baseminor), count, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief: 注册设备号
|
|
||||||
/// @parameter: device_number: 设备号,主设备号如果为0,则动态分配
|
|
||||||
/// minorct: 次设备号数量
|
|
||||||
/// name: 字符设备名
|
|
||||||
/// @return: 如果注册成功,返回设备号,否则,返回错误码
|
|
||||||
fn __register_chardev_region(
|
|
||||||
device_number: DeviceNumber,
|
|
||||||
minorct: usize,
|
|
||||||
name: &'static str,
|
|
||||||
) -> Result<DeviceNumber, SystemError> {
|
|
||||||
let mut major = device_number.major();
|
|
||||||
let baseminor = device_number.minor();
|
|
||||||
if major >= CHARDEV_MAJOR_MAX {
|
|
||||||
kerror!(
|
|
||||||
"CHARDEV {} major requested {} is greater than the maximum {}\n",
|
|
||||||
name,
|
|
||||||
major,
|
|
||||||
CHARDEV_MAJOR_MAX - 1
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if minorct > MINOR_MASK + 1 - baseminor {
|
|
||||||
kerror!("CHARDEV {} minor range requested ({}-{}) is out of range of maximum range ({}-{}) for a single major\n",
|
|
||||||
name, baseminor, baseminor + minorct - 1, 0, MINOR_MASK);
|
|
||||||
}
|
|
||||||
let chardev = CharDeviceStruct::new(mkdev(major, baseminor), minorct, name);
|
|
||||||
if major == 0 {
|
|
||||||
// 如果主设备号为0,则自动分配主设备号
|
|
||||||
major = Self::find_dynamic_major().expect("Find synamic major error.\n");
|
|
||||||
}
|
|
||||||
if let Some(items) = CHARDEVS.0.lock().0.get_mut(Self::major_to_index(major)) {
|
|
||||||
let mut insert_index: usize = 0;
|
|
||||||
for (index, item) in items.iter().enumerate() {
|
|
||||||
insert_index = index;
|
|
||||||
match item.device_number().major().cmp(&major) {
|
|
||||||
Ordering::Less => continue,
|
|
||||||
Ordering::Greater => {
|
|
||||||
break; // 大于则向后插入
|
|
||||||
}
|
|
||||||
Ordering::Equal => {
|
|
||||||
if item.device_number().minor() + item.minorct() <= baseminor {
|
|
||||||
continue; // 下一个主设备号大于或者次设备号大于被插入的次设备号最大值
|
|
||||||
}
|
|
||||||
if item.base_minor() >= baseminor + minorct {
|
|
||||||
break; // 在此处插入
|
|
||||||
}
|
|
||||||
return Err(SystemError::EBUSY); // 存在重合的次设备号
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
items.insert(insert_index, chardev);
|
|
||||||
}
|
|
||||||
return Ok(mkdev(major, baseminor));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief: 注销设备号
|
|
||||||
/// @parameter: major: 主设备号,如果为0,动态分配
|
|
||||||
/// baseminor: 起始次设备号
|
|
||||||
/// minorct: 次设备号数量
|
|
||||||
/// @return: 如果注销成功,返回(),否则,返回错误码
|
|
||||||
fn __unregister_chardev_region(
|
|
||||||
device_number: DeviceNumber,
|
|
||||||
minorct: usize,
|
|
||||||
) -> Result<(), SystemError> {
|
|
||||||
if let Some(items) = CHARDEVS
|
|
||||||
.0
|
|
||||||
.lock()
|
|
||||||
.0
|
|
||||||
.get_mut(Self::major_to_index(device_number.major()))
|
|
||||||
{
|
|
||||||
for (index, item) in items.iter().enumerate() {
|
|
||||||
if item.device_number() == device_number && item.minorct() == minorct {
|
|
||||||
// 设备号和数量都相等
|
|
||||||
items.remove(index);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Err(SystemError::EBUSY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief: 字符设备注册
|
|
||||||
/// @parameter: cdev: 字符设备实例
|
|
||||||
/// dev_t: 字符设备号
|
|
||||||
/// range: 次设备号范围
|
|
||||||
/// @return: none
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn cdev_add(cdev: Arc<dyn CharDevice>, dev_t: DeviceNumber, range: usize) {
|
|
||||||
if Into::<usize>::into(dev_t) == 0 {
|
|
||||||
kerror!("Device number can't be 0!\n");
|
|
||||||
}
|
|
||||||
kobj_map(CDEVMAP.clone(), dev_t, range, cdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief: 字符设备注销
|
|
||||||
/// @parameter: dev_t: 字符设备号
|
|
||||||
/// range: 次设备号范围
|
|
||||||
/// @return: none
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn cdev_del(dev_t: DeviceNumber, range: usize) {
|
|
||||||
kobj_unmap(CDEVMAP.clone(), dev_t, range);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use super::{
|
use super::{
|
||||||
device_register, device_unregister,
|
device_register, device_unregister,
|
||||||
driver::{driver_register, driver_unregister, Driver, DriverError},
|
driver::{driver_register, driver_unregister, DriverError},
|
||||||
Device, DeviceError, DeviceState, IdTable,
|
Device, DeviceError, DeviceState, IdTable,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
driver::Driver,
|
||||||
filesystem::{
|
filesystem::{
|
||||||
sysfs::{
|
sysfs::{
|
||||||
bus::{sys_bus_init, sys_bus_register},
|
bus::{sys_bus_init, sys_bus_register},
|
||||||
@ -176,7 +177,7 @@ impl LockedBusManager {
|
|||||||
/// @return: 成功:() 失败:DeviceError
|
/// @return: 成功:() 失败:DeviceError
|
||||||
pub fn bus_register<T: Bus>(bus: Arc<T>) -> Result<(), DeviceError> {
|
pub fn bus_register<T: Bus>(bus: Arc<T>) -> Result<(), DeviceError> {
|
||||||
BUS_MANAGER.add_bus(bus.id_table(), bus.clone());
|
BUS_MANAGER.add_bus(bus.id_table(), bus.clone());
|
||||||
match sys_bus_register(&bus.id_table().to_name()) {
|
match sys_bus_register(&bus.id_table().name()) {
|
||||||
Ok(inode) => {
|
Ok(inode) => {
|
||||||
let _ = sys_bus_init(&inode);
|
let _ = sys_bus_init(&inode);
|
||||||
return device_register(bus);
|
return device_register(bus);
|
||||||
@ -197,7 +198,7 @@ pub fn bus_unregister<T: Bus>(bus: Arc<T>) -> Result<(), DeviceError> {
|
|||||||
/// @brief: 总线驱动注册,将总线驱动加入全局总线管理器中
|
/// @brief: 总线驱动注册,将总线驱动加入全局总线管理器中
|
||||||
/// @parameter bus: Bus设备驱动实体
|
/// @parameter bus: Bus设备驱动实体
|
||||||
/// @return: 成功:() 失败:DeviceError
|
/// @return: 成功:() 失败:DeviceError
|
||||||
pub fn bus_driver_register<T: BusDriver>(bus_driver: Arc<T>) -> Result<(), DriverError> {
|
pub fn bus_driver_register(bus_driver: Arc<dyn BusDriver>) -> Result<(), DriverError> {
|
||||||
BUS_MANAGER.add_driver(bus_driver.id_table(), bus_driver.clone());
|
BUS_MANAGER.add_driver(bus_driver.id_table(), bus_driver.clone());
|
||||||
return driver_register(bus_driver);
|
return driver_register(bus_driver);
|
||||||
}
|
}
|
||||||
@ -206,7 +207,7 @@ pub fn bus_driver_register<T: BusDriver>(bus_driver: Arc<T>) -> Result<(), Drive
|
|||||||
/// @parameter bus: Bus设备驱动实体
|
/// @parameter bus: Bus设备驱动实体
|
||||||
/// @return: 成功:() 失败:DeviceError
|
/// @return: 成功:() 失败:DeviceError
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn bus_driver_unregister<T: BusDriver>(bus_driver: Arc<T>) -> Result<(), DriverError> {
|
pub fn bus_driver_unregister(bus_driver: Arc<dyn BusDriver>) -> Result<(), DriverError> {
|
||||||
BUS_MANAGER.add_driver(bus_driver.id_table(), bus_driver.clone());
|
BUS_MANAGER.add_driver(bus_driver.id_table(), bus_driver.clone());
|
||||||
return driver_unregister(bus_driver);
|
return driver_unregister(bus_driver);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use super::{IdTable, KObject};
|
use super::IdTable;
|
||||||
use crate::{filesystem::vfs::IndexNode, libs::spinlock::SpinLock, syscall::SystemError};
|
use crate::{
|
||||||
|
driver::Driver, filesystem::vfs::IndexNode, libs::spinlock::SpinLock, syscall::SystemError,
|
||||||
|
};
|
||||||
use alloc::{collections::BTreeMap, sync::Arc};
|
use alloc::{collections::BTreeMap, sync::Arc};
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
|
||||||
@ -11,42 +13,25 @@ lazy_static! {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
pub enum DriverError {
|
pub enum DriverError {
|
||||||
ProbeError,
|
ProbeError, // 探测设备失败(该驱动不能初始化这个设备)
|
||||||
RegisterError,
|
RegisterError, // 设备注册失败
|
||||||
|
AllocateResourceError, // 获取设备所需资源失败
|
||||||
|
UnsupportedOperation, // 不支持的操作
|
||||||
|
UnInitialized, // 未初始化
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<SystemError> for DriverError {
|
impl Into<SystemError> for DriverError {
|
||||||
fn into(self) -> SystemError {
|
fn into(self) -> SystemError {
|
||||||
match self {
|
match self {
|
||||||
DriverError::ProbeError => SystemError::EIO,
|
DriverError::ProbeError => SystemError::ENODEV,
|
||||||
DriverError::RegisterError => SystemError::EIO,
|
DriverError::RegisterError => SystemError::ENODEV,
|
||||||
|
DriverError::AllocateResourceError => SystemError::EIO,
|
||||||
|
DriverError::UnsupportedOperation => SystemError::EIO,
|
||||||
|
DriverError::UnInitialized => SystemError::ENODEV,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief: 所有驱动驱动都应该实现该trait
|
|
||||||
pub trait Driver: KObject {
|
|
||||||
/// @brief: 本函数用于实现动态转换
|
|
||||||
/// @parameter: None
|
|
||||||
/// @return: any
|
|
||||||
fn as_any_ref(&'static self) -> &'static dyn core::any::Any;
|
|
||||||
|
|
||||||
/// @brief: 获取驱动驱动标识符
|
|
||||||
/// @parameter: None
|
|
||||||
/// @return: 该驱动驱动唯一标识符
|
|
||||||
fn id_table(&self) -> IdTable;
|
|
||||||
|
|
||||||
/// @brief: 设置驱动的sys information
|
|
||||||
/// @parameter id_table: 驱动标识符,用于唯一标识该驱动
|
|
||||||
/// @return: 驱动实例
|
|
||||||
fn set_sys_info(&self, sys_info: Option<Arc<dyn IndexNode>>);
|
|
||||||
|
|
||||||
/// @brief: 获取驱动的sys information
|
|
||||||
/// @parameter id_table: 驱动标识符,用于唯一标识该驱动
|
|
||||||
/// @return: 驱动实例
|
|
||||||
fn sys_info(&self) -> Option<Arc<dyn IndexNode>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief: 驱动管理器(锁)
|
/// @brief: 驱动管理器(锁)
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LockedDriverManager(SpinLock<DriverManager>);
|
pub struct LockedDriverManager(SpinLock<DriverManager>);
|
||||||
@ -111,7 +96,7 @@ pub struct DriverManager {
|
|||||||
impl DriverManager {
|
impl DriverManager {
|
||||||
/// @brief: 创建一个新的设备管理器
|
/// @brief: 创建一个新的设备管理器
|
||||||
/// @parameter: None
|
/// @parameter: None
|
||||||
/// @return: DeviceManager实体
|
/// @return: Manager实体
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new() -> DriverManager {
|
fn new() -> DriverManager {
|
||||||
DriverManager {
|
DriverManager {
|
||||||
@ -124,7 +109,7 @@ impl DriverManager {
|
|||||||
/// @brief: 驱动注册
|
/// @brief: 驱动注册
|
||||||
/// @parameter: name: 驱动名
|
/// @parameter: name: 驱动名
|
||||||
/// @return: 操作成功,返回(),操作失败,返回错误码
|
/// @return: 操作成功,返回(),操作失败,返回错误码
|
||||||
pub fn driver_register<T: Driver>(driver: Arc<T>) -> Result<(), DriverError> {
|
pub fn driver_register(driver: Arc<dyn Driver>) -> Result<(), DriverError> {
|
||||||
DRIVER_MANAGER.add_driver(driver.id_table(), driver);
|
DRIVER_MANAGER.add_driver(driver.id_table(), driver);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -133,7 +118,7 @@ pub fn driver_register<T: Driver>(driver: Arc<T>) -> Result<(), DriverError> {
|
|||||||
/// @parameter: name: 驱动名
|
/// @parameter: name: 驱动名
|
||||||
/// @return: 操作成功,返回(),操作失败,返回错误码
|
/// @return: 操作成功,返回(),操作失败,返回错误码
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn driver_unregister<T: Driver>(driver: Arc<T>) -> Result<(), DriverError> {
|
pub fn driver_unregister(driver: Arc<dyn Driver>) -> Result<(), DriverError> {
|
||||||
DRIVER_MANAGER.add_driver(driver.id_table(), driver);
|
DRIVER_MANAGER.add_driver(driver.id_table(), driver);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
16
kernel/src/driver/base/device/init.rs
Normal file
16
kernel/src/driver/base/device/init.rs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
use crate::{driver::uart::uart_device::uart_init, kinfo, syscall::SystemError};
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn rs_device_init() -> i32 {
|
||||||
|
let result = device_init()
|
||||||
|
.map(|_| 0)
|
||||||
|
.unwrap_or_else(|e| e.to_posix_errno());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn device_init() -> Result<(), SystemError> {
|
||||||
|
uart_init()?;
|
||||||
|
kinfo!("device init success");
|
||||||
|
return Ok(());
|
||||||
|
}
|
@ -1,6 +1,11 @@
|
|||||||
use alloc::{collections::BTreeMap, string::String, sync::Arc};
|
use alloc::{
|
||||||
|
collections::BTreeMap,
|
||||||
|
string::{String, ToString},
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
driver::base::map::{LockedDevsMap, LockedKObjMap},
|
||||||
filesystem::{
|
filesystem::{
|
||||||
sysfs::{
|
sysfs::{
|
||||||
devices::{sys_device_register, sys_device_unregister},
|
devices::{sys_device_register, sys_device_unregister},
|
||||||
@ -13,18 +18,113 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use core::{any::Any, fmt::Debug};
|
use core::{any::Any, fmt::Debug};
|
||||||
|
|
||||||
|
use super::platform::CompatibleTable;
|
||||||
|
|
||||||
pub mod bus;
|
pub mod bus;
|
||||||
pub mod driver;
|
pub mod driver;
|
||||||
|
pub mod init;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref DEVICE_MANAGER: Arc<LockedDeviceManager> = Arc::new(LockedDeviceManager::new());
|
pub static ref DEVICE_MANAGER: Arc<LockedDeviceManager> = Arc::new(LockedDeviceManager::new());
|
||||||
}
|
}
|
||||||
|
lazy_static! {
|
||||||
|
// 全局字符设备号管理实例
|
||||||
|
pub static ref CHARDEVS: Arc<LockedDevsMap> = Arc::new(LockedDevsMap::default());
|
||||||
|
|
||||||
|
// 全局块设备管理实例
|
||||||
|
pub static ref BLOCKDEVS: Arc<LockedDevsMap> = Arc::new(LockedDevsMap::default());
|
||||||
|
|
||||||
|
// 全局设备管理实例
|
||||||
|
pub static ref DEVMAP: Arc<LockedKObjMap> = Arc::new(LockedKObjMap::default());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
pub trait KObject: Any + Send + Sync + Debug {}
|
pub trait KObject: Any + Send + Sync + Debug {}
|
||||||
|
/// @brief 设备应该实现的操作
|
||||||
|
/// @usage Device::read_at()
|
||||||
|
pub trait Device: KObject {
|
||||||
|
// TODO: 待实现 open, close
|
||||||
|
fn as_any_ref(&self) -> &dyn core::any::Any;
|
||||||
|
/// @brief: 获取设备类型
|
||||||
|
/// @parameter: None
|
||||||
|
/// @return: 实现该trait的设备所属类型
|
||||||
|
fn dev_type(&self) -> DeviceType;
|
||||||
|
|
||||||
/// @brief: 设备号实例
|
/// @brief: 获取设备标识
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
|
/// @parameter: None
|
||||||
pub struct DeviceNumber(usize);
|
/// @return: 该设备唯一标识
|
||||||
|
fn id_table(&self) -> IdTable;
|
||||||
|
|
||||||
|
/// @brief: 设置sysfs info
|
||||||
|
/// @parameter: None
|
||||||
|
/// @return: 该设备唯一标识
|
||||||
|
fn set_sys_info(&self, _sys_info: Option<Arc<dyn IndexNode>>);
|
||||||
|
|
||||||
|
/// @brief: 获取设备的sys information
|
||||||
|
/// @parameter id_table: 设备标识符,用于唯一标识该设备
|
||||||
|
/// @return: 设备实例
|
||||||
|
fn sys_info(&self) -> Option<Arc<dyn IndexNode>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂定是不可修改的,在初始化的时候就要确定。以后可能会包括例如硬件中断包含的信息
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DevicePrivateData {
|
||||||
|
id_table: IdTable,
|
||||||
|
resource: Option<DeviceResource>,
|
||||||
|
compatible_table: CompatibleTable,
|
||||||
|
state: DeviceState,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DevicePrivateData {
|
||||||
|
pub fn new(
|
||||||
|
id_table: IdTable,
|
||||||
|
resource: Option<DeviceResource>,
|
||||||
|
compatible_table: CompatibleTable,
|
||||||
|
state: DeviceState,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
id_table,
|
||||||
|
resource,
|
||||||
|
compatible_table,
|
||||||
|
state,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id_table(&self) -> &IdTable {
|
||||||
|
&self.id_table
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn state(&self) -> DeviceState {
|
||||||
|
self.state
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn resource(&self) -> Option<&DeviceResource> {
|
||||||
|
self.resource.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compatible_table(&self) -> &CompatibleTable {
|
||||||
|
&self.compatible_table
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_state(&mut self, state: DeviceState) {
|
||||||
|
self.state = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DeviceResource {
|
||||||
|
//可能会用来保存例如 IRQ PWM 内存地址等需要申请的资源,将来由资源管理器+Framework框架进行管理。
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DeviceResource {
|
||||||
|
fn default() -> Self {
|
||||||
|
return Self {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int_like!(DeviceNumber, usize);
|
||||||
|
|
||||||
impl Default for DeviceNumber {
|
impl Default for DeviceNumber {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
@ -44,6 +144,12 @@ impl Into<usize> for DeviceNumber {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl core::hash::Hash for DeviceNumber {
|
||||||
|
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
self.0.hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl DeviceNumber {
|
impl DeviceNumber {
|
||||||
/// @brief: 设备号创建
|
/// @brief: 设备号创建
|
||||||
/// @parameter: dev_t: 设备号
|
/// @parameter: dev_t: 设备号
|
||||||
@ -65,6 +171,10 @@ impl DeviceNumber {
|
|||||||
pub fn minor(&self) -> usize {
|
pub fn minor(&self) -> usize {
|
||||||
self.0 & 0xfffff
|
self.0 & 0xfffff
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_major_minor(major: usize, minor: usize) -> usize {
|
||||||
|
((major & 0xffffff) << 8) | (minor & 0xff)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief: 根据主次设备号创建设备号实例
|
/// @brief: 根据主次设备号创建设备号实例
|
||||||
@ -92,7 +202,7 @@ pub enum DeviceType {
|
|||||||
|
|
||||||
/// @brief: 设备标识符类型
|
/// @brief: 设备标识符类型
|
||||||
#[derive(Debug, Clone, Hash, PartialOrd, PartialEq, Ord, Eq)]
|
#[derive(Debug, Clone, Hash, PartialOrd, PartialEq, Ord, Eq)]
|
||||||
pub struct IdTable(&'static str, u32);
|
pub struct IdTable(String, DeviceNumber);
|
||||||
|
|
||||||
/// @brief: 设备标识符操作方法集
|
/// @brief: 设备标识符操作方法集
|
||||||
impl IdTable {
|
impl IdTable {
|
||||||
@ -100,18 +210,29 @@ impl IdTable {
|
|||||||
/// @parameter name: 设备名
|
/// @parameter name: 设备名
|
||||||
/// @parameter id: 设备id
|
/// @parameter id: 设备id
|
||||||
/// @return: 设备标识符
|
/// @return: 设备标识符
|
||||||
pub fn new(name: &'static str, id: u32) -> IdTable {
|
pub fn new(name: String, id: DeviceNumber) -> IdTable {
|
||||||
Self(name, id)
|
Self(name, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief: 将设备标识符转换成name
|
/// @brief: 将设备标识符转换成name
|
||||||
/// @parameter None
|
/// @parameter None
|
||||||
/// @return: 设备名
|
/// @return: 设备名
|
||||||
pub fn to_name(&self) -> String {
|
pub fn name(&self) -> String {
|
||||||
return format!("{}:{}", self.0, self.1);
|
return format!("{}:{:?}", self.0, self.1 .0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn device_number(&self) -> DeviceNumber {
|
||||||
|
return self.1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for IdTable {
|
||||||
|
fn default() -> Self {
|
||||||
|
IdTable("unknown".to_string(), DeviceNumber::new(0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 以现在的模型,设备在加载到系统中就是已经初始化的状态了,因此可以考虑把这个删掉
|
||||||
/// @brief: 设备当前状态
|
/// @brief: 设备当前状态
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum DeviceState {
|
pub enum DeviceState {
|
||||||
@ -121,14 +242,17 @@ pub enum DeviceState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// @brief: 设备错误类型
|
/// @brief: 设备错误类型
|
||||||
|
#[allow(dead_code)]
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum DeviceError {
|
pub enum DeviceError {
|
||||||
DriverExists, // 设备已存在
|
DriverExists, // 设备已存在
|
||||||
DeviceExists, // 驱动已存在
|
DeviceExists, // 驱动已存在
|
||||||
InitializeFailed, // 初始化错误
|
InitializeFailed, // 初始化错误
|
||||||
NoDeviceForDriver, // 没有合适的设备匹配驱动
|
NotInitialized, // 未初始化的设备
|
||||||
NoDriverForDevice, // 没有合适的驱动匹配设备
|
NoDeviceForDriver, // 没有合适的设备匹配驱动
|
||||||
RegisterError, // 注册失败
|
NoDriverForDevice, // 没有合适的驱动匹配设备
|
||||||
|
RegisterError, // 注册失败
|
||||||
|
UnsupportedOperation, // 不支持的操作
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<SystemError> for DeviceError {
|
impl Into<SystemError> for DeviceError {
|
||||||
@ -137,9 +261,11 @@ impl Into<SystemError> for DeviceError {
|
|||||||
DeviceError::DriverExists => SystemError::EEXIST,
|
DeviceError::DriverExists => SystemError::EEXIST,
|
||||||
DeviceError::DeviceExists => SystemError::EEXIST,
|
DeviceError::DeviceExists => SystemError::EEXIST,
|
||||||
DeviceError::InitializeFailed => SystemError::EIO,
|
DeviceError::InitializeFailed => SystemError::EIO,
|
||||||
|
DeviceError::NotInitialized => SystemError::ENODEV,
|
||||||
DeviceError::NoDeviceForDriver => SystemError::ENODEV,
|
DeviceError::NoDeviceForDriver => SystemError::ENODEV,
|
||||||
DeviceError::NoDriverForDevice => SystemError::ENODEV,
|
DeviceError::NoDriverForDevice => SystemError::ENODEV,
|
||||||
DeviceError::RegisterError => SystemError::EIO,
|
DeviceError::RegisterError => SystemError::EIO,
|
||||||
|
DeviceError::UnsupportedOperation => SystemError::EIO,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,34 +292,6 @@ impl From<DeviceState> for u32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief: 所有设备都应该实现该trait
|
|
||||||
pub trait Device: KObject {
|
|
||||||
/// @brief: 本函数用于实现动态转换
|
|
||||||
/// @parameter: None
|
|
||||||
/// @return: any
|
|
||||||
fn as_any_ref(&'static self) -> &'static dyn core::any::Any;
|
|
||||||
|
|
||||||
/// @brief: 获取设备类型
|
|
||||||
/// @parameter: None
|
|
||||||
/// @return: 实现该trait的设备所属类型
|
|
||||||
fn dev_type(&self) -> DeviceType;
|
|
||||||
|
|
||||||
/// @brief: 获取设备标识
|
|
||||||
/// @parameter: None
|
|
||||||
/// @return: 该设备唯一标识
|
|
||||||
fn id_table(&self) -> IdTable;
|
|
||||||
|
|
||||||
/// @brief: 设置sysfs info
|
|
||||||
/// @parameter: None
|
|
||||||
/// @return: 该设备唯一标识
|
|
||||||
fn set_sys_info(&self, sys_info: Option<Arc<dyn IndexNode>>);
|
|
||||||
|
|
||||||
/// @brief: 获取设备的sys information
|
|
||||||
/// @parameter id_table: 设备标识符,用于唯一标识该设备
|
|
||||||
/// @return: 设备实例
|
|
||||||
fn sys_info(&self) -> Option<Arc<dyn IndexNode>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Device管理器(锁)
|
/// @brief Device管理器(锁)
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct LockedDeviceManager(SpinLock<DeviceManager>);
|
pub struct LockedDeviceManager(SpinLock<DeviceManager>);
|
||||||
@ -269,7 +367,7 @@ impl DeviceManager {
|
|||||||
/// @return: 操作成功,返回(),操作失败,返回错误码
|
/// @return: 操作成功,返回(),操作失败,返回错误码
|
||||||
pub fn device_register<T: Device>(device: Arc<T>) -> Result<(), DeviceError> {
|
pub fn device_register<T: Device>(device: Arc<T>) -> Result<(), DeviceError> {
|
||||||
DEVICE_MANAGER.add_device(device.id_table(), device.clone());
|
DEVICE_MANAGER.add_device(device.id_table(), device.clone());
|
||||||
match sys_device_register(&device.id_table().to_name()) {
|
match sys_device_register(&device.id_table().name()) {
|
||||||
Ok(sys_info) => {
|
Ok(sys_info) => {
|
||||||
device.set_sys_info(Some(sys_info));
|
device.set_sys_info(Some(sys_info));
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -283,7 +381,7 @@ pub fn device_register<T: Device>(device: Arc<T>) -> Result<(), DeviceError> {
|
|||||||
/// @return: 操作成功,返回(),操作失败,返回错误码
|
/// @return: 操作成功,返回(),操作失败,返回错误码
|
||||||
pub fn device_unregister<T: Device>(device: Arc<T>) -> Result<(), DeviceError> {
|
pub fn device_unregister<T: Device>(device: Arc<T>) -> Result<(), DeviceError> {
|
||||||
DEVICE_MANAGER.add_device(device.id_table(), device.clone());
|
DEVICE_MANAGER.add_device(device.id_table(), device.clone());
|
||||||
match sys_device_unregister(&device.id_table().to_name()) {
|
match sys_device_unregister(&device.id_table().name()) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
device.set_sys_info(None);
|
device.set_sys_info(None);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -1,8 +1,23 @@
|
|||||||
use super::device::{mkdev, DeviceNumber, KObject};
|
use core::cmp::Ordering;
|
||||||
use crate::libs::spinlock::SpinLock;
|
|
||||||
|
use super::{
|
||||||
|
block::block_device::BlockDevice,
|
||||||
|
char::CharDevice,
|
||||||
|
device::{mkdev, DeviceNumber, IdTable, KObject, BLOCKDEVS, CHARDEVS, DEVICE_MANAGER, DEVMAP},
|
||||||
|
};
|
||||||
|
use crate::{kerror, libs::spinlock::SpinLock, syscall::SystemError};
|
||||||
use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
|
use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
|
||||||
|
|
||||||
const KOBJMAP_HASH_SIZE: usize = 255;
|
const KOBJMAP_HASH_SIZE: usize = 255;
|
||||||
|
const DEV_MAJOR_HASH_SIZE: usize = 255;
|
||||||
|
const DEV_MAJOR_MAX: usize = 512;
|
||||||
|
const MINOR_BITS: usize = 20;
|
||||||
|
const MINOR_MASK: usize = 1 << MINOR_BITS - 1;
|
||||||
|
/* Marks the bottom of the first segment of free char majors */
|
||||||
|
const DEV_MAJOR_DYN_END: usize = 234;
|
||||||
|
/* Marks the top and bottom of the second segment of free char majors */
|
||||||
|
const DEV_MAJOR_DYN_EXT_START: usize = 511;
|
||||||
|
const DEV_MAJOR_DYN_EXT_END: usize = 384;
|
||||||
|
|
||||||
/// @brief: 字符设备与块设备管理结构体
|
/// @brief: 字符设备与块设备管理结构体
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -96,3 +111,435 @@ pub fn kobj_lookup(domain: Arc<LockedKObjMap>, dev_t: DeviceNumber) -> Option<Ar
|
|||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 管理字符设备号的map(加锁)
|
||||||
|
pub struct LockedDevsMap(SpinLock<DevsMap>);
|
||||||
|
|
||||||
|
impl Default for LockedDevsMap {
|
||||||
|
fn default() -> Self {
|
||||||
|
LockedDevsMap(SpinLock::new(DevsMap::default()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 管理字符设备号的map
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct DevsMap(Vec<Vec<DeviceStruct>>);
|
||||||
|
|
||||||
|
impl Default for DevsMap {
|
||||||
|
fn default() -> Self {
|
||||||
|
DevsMap(vec![Vec::new(); DEV_MAJOR_HASH_SIZE])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字符设备在系统中的实例,devfs通过该结构与实际字符设备进行联系
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DeviceStruct {
|
||||||
|
dev_t: DeviceNumber, //起始设备号
|
||||||
|
minorct: usize, // 次设备号数量
|
||||||
|
name: &'static str, //字符设备名
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceStruct {
|
||||||
|
/// @brief: 创建实例
|
||||||
|
/// @parameter: dev_t: 设备号
|
||||||
|
/// minorct: 次设备号数量
|
||||||
|
/// name: 字符设备名
|
||||||
|
/// char: 字符设备实例
|
||||||
|
/// @return: 实例
|
||||||
|
///
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new(dev_t: DeviceNumber, minorct: usize, name: &'static str) -> Self {
|
||||||
|
Self {
|
||||||
|
dev_t,
|
||||||
|
minorct,
|
||||||
|
name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: 获取起始次设备号
|
||||||
|
/// @parameter: None
|
||||||
|
/// @return: 起始设备号
|
||||||
|
///
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn device_number(&self) -> DeviceNumber {
|
||||||
|
self.dev_t
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: 获取起始次设备号
|
||||||
|
/// @parameter: None
|
||||||
|
/// @return: 起始设备号
|
||||||
|
///
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn base_minor(&self) -> usize {
|
||||||
|
self.dev_t.minor()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: 获取次设备号数量
|
||||||
|
/// @parameter: None
|
||||||
|
/// @return: 次设备号数量
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn minorct(&self) -> usize {
|
||||||
|
self.minorct
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 这下面是考虑到 块设备的注册和字符设备的注册在设备号的自动分配上要有所区别,
|
||||||
|
// 暂时没有去查具体是怎么做区分的,因此暂时还是一样的
|
||||||
|
|
||||||
|
/// @brief 块设备框架函数集
|
||||||
|
pub struct BlockDeviceOps;
|
||||||
|
|
||||||
|
impl BlockDeviceOps {
|
||||||
|
/// @brief: 主设备号转下标
|
||||||
|
/// @parameter: major: 主设备号
|
||||||
|
/// @return: 返回下标
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn major_to_index(major: usize) -> usize {
|
||||||
|
return major % DEV_MAJOR_HASH_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: 动态获取主设备号
|
||||||
|
/// @parameter: None
|
||||||
|
/// @return: 如果成功,返回主设备号,否则,返回错误码
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn find_dynamic_major() -> Result<usize, SystemError> {
|
||||||
|
let blockdevs = BLOCKDEVS.0.lock();
|
||||||
|
// 寻找主设备号为234~255的设备
|
||||||
|
for index in (DEV_MAJOR_DYN_END..DEV_MAJOR_HASH_SIZE).rev() {
|
||||||
|
if let Some(item) = blockdevs.0.get(index) {
|
||||||
|
if item.is_empty() {
|
||||||
|
return Ok(index); // 返回可用的主设备号
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 寻找主设备号在384~511的设备
|
||||||
|
for index in (DEV_MAJOR_DYN_EXT_END + 1..DEV_MAJOR_DYN_EXT_START + 1).rev() {
|
||||||
|
if let Some(blockdevss) = blockdevs.0.get(Self::major_to_index(index)) {
|
||||||
|
let mut flag = true;
|
||||||
|
for item in blockdevss {
|
||||||
|
if item.device_number().major() == index {
|
||||||
|
flag = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if flag {
|
||||||
|
// 如果数组中不存在主设备号等于index的设备
|
||||||
|
return Ok(index); // 返回可用的主设备号
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(SystemError::EBUSY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: 注册设备号,该函数需要指定主设备号
|
||||||
|
/// @parameter: from: 主设备号
|
||||||
|
/// count: 次设备号数量
|
||||||
|
/// name: 字符设备名
|
||||||
|
/// @return: 如果注册成功,返回设备号,否则,返回错误码
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn register_blockdev_region(
|
||||||
|
from: DeviceNumber,
|
||||||
|
count: usize,
|
||||||
|
name: &'static str,
|
||||||
|
) -> Result<DeviceNumber, SystemError> {
|
||||||
|
Self::__register_blockdev_region(from, count, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: 注册设备号,该函数自动分配主设备号
|
||||||
|
/// @parameter: baseminor: 主设备号
|
||||||
|
/// count: 次设备号数量
|
||||||
|
/// name: 字符设备名
|
||||||
|
/// @return: 如果注册成功,返回,否则,返回false
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn alloc_blockdev_region(
|
||||||
|
baseminor: usize,
|
||||||
|
count: usize,
|
||||||
|
name: &'static str,
|
||||||
|
) -> Result<DeviceNumber, SystemError> {
|
||||||
|
Self::__register_blockdev_region(mkdev(0, baseminor), count, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: 注册设备号
|
||||||
|
/// @parameter: device_number: 设备号,主设备号如果为0,则动态分配
|
||||||
|
/// minorct: 次设备号数量
|
||||||
|
/// name: 字符设备名
|
||||||
|
/// @return: 如果注册成功,返回设备号,否则,返回错误码
|
||||||
|
fn __register_blockdev_region(
|
||||||
|
device_number: DeviceNumber,
|
||||||
|
minorct: usize,
|
||||||
|
name: &'static str,
|
||||||
|
) -> Result<DeviceNumber, SystemError> {
|
||||||
|
let mut major = device_number.major();
|
||||||
|
let baseminor = device_number.minor();
|
||||||
|
if major >= DEV_MAJOR_MAX {
|
||||||
|
kerror!(
|
||||||
|
"DEV {} major requested {} is greater than the maximum {}\n",
|
||||||
|
name,
|
||||||
|
major,
|
||||||
|
DEV_MAJOR_MAX - 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if minorct > MINOR_MASK + 1 - baseminor {
|
||||||
|
kerror!("DEV {} minor range requested ({}-{}) is out of range of maximum range ({}-{}) for a single major\n",
|
||||||
|
name, baseminor, baseminor + minorct - 1, 0, MINOR_MASK);
|
||||||
|
}
|
||||||
|
let blockdev = DeviceStruct::new(mkdev(major, baseminor), minorct, name);
|
||||||
|
if major == 0 {
|
||||||
|
// 如果主设备号为0,则自动分配主设备号
|
||||||
|
major = Self::find_dynamic_major().expect("Find synamic major error.\n");
|
||||||
|
}
|
||||||
|
if let Some(items) = BLOCKDEVS.0.lock().0.get_mut(Self::major_to_index(major)) {
|
||||||
|
let mut insert_index: usize = 0;
|
||||||
|
for (index, item) in items.iter().enumerate() {
|
||||||
|
insert_index = index;
|
||||||
|
match item.device_number().major().cmp(&major) {
|
||||||
|
Ordering::Less => continue,
|
||||||
|
Ordering::Greater => {
|
||||||
|
break; // 大于则向后插入
|
||||||
|
}
|
||||||
|
Ordering::Equal => {
|
||||||
|
if item.device_number().minor() + item.minorct() <= baseminor {
|
||||||
|
continue; // 下一个主设备号大于或者次设备号大于被插入的次设备号最大值
|
||||||
|
}
|
||||||
|
if item.base_minor() >= baseminor + minorct {
|
||||||
|
break; // 在此处插入
|
||||||
|
}
|
||||||
|
return Err(SystemError::EBUSY); // 存在重合的次设备号
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items.insert(insert_index, blockdev);
|
||||||
|
}
|
||||||
|
return Ok(mkdev(major, baseminor));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: 注销设备号
|
||||||
|
/// @parameter: major: 主设备号,如果为0,动态分配
|
||||||
|
/// baseminor: 起始次设备号
|
||||||
|
/// minorct: 次设备号数量
|
||||||
|
/// @return: 如果注销成功,返回(),否则,返回错误码
|
||||||
|
fn __unregister_blockdev_region(
|
||||||
|
device_number: DeviceNumber,
|
||||||
|
minorct: usize,
|
||||||
|
) -> Result<(), SystemError> {
|
||||||
|
if let Some(items) = BLOCKDEVS
|
||||||
|
.0
|
||||||
|
.lock()
|
||||||
|
.0
|
||||||
|
.get_mut(Self::major_to_index(device_number.major()))
|
||||||
|
{
|
||||||
|
for (index, item) in items.iter().enumerate() {
|
||||||
|
if item.device_number() == device_number && item.minorct() == minorct {
|
||||||
|
// 设备号和数量都相等
|
||||||
|
items.remove(index);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(SystemError::EBUSY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: 块设备注册
|
||||||
|
/// @parameter: cdev: 字符设备实例
|
||||||
|
/// dev_t: 字符设备号
|
||||||
|
/// range: 次设备号范围
|
||||||
|
/// @return: none
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn bdev_add(bdev: Arc<dyn BlockDevice>, id_table: IdTable) {
|
||||||
|
if Into::<usize>::into(id_table.device_number()) == 0 {
|
||||||
|
kerror!("Device number can't be 0!\n");
|
||||||
|
}
|
||||||
|
DEVICE_MANAGER.add_device(id_table, bdev.device())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: block设备注销
|
||||||
|
/// @parameter: dev_t: 字符设备号
|
||||||
|
/// range: 次设备号范围
|
||||||
|
/// @return: none
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn bdev_del(_devnum: DeviceNumber, _range: usize) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 字符设备框架函数集
|
||||||
|
pub struct CharDevOps;
|
||||||
|
|
||||||
|
impl CharDevOps {
|
||||||
|
/// @brief: 主设备号转下标
|
||||||
|
/// @parameter: major: 主设备号
|
||||||
|
/// @return: 返回下标
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn major_to_index(major: usize) -> usize {
|
||||||
|
return major % DEV_MAJOR_HASH_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: 动态获取主设备号
|
||||||
|
/// @parameter: None
|
||||||
|
/// @return: 如果成功,返回主设备号,否则,返回错误码
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn find_dynamic_major() -> Result<usize, SystemError> {
|
||||||
|
let chardevs = CHARDEVS.0.lock();
|
||||||
|
// 寻找主设备号为234~255的设备
|
||||||
|
for index in (DEV_MAJOR_DYN_END..DEV_MAJOR_HASH_SIZE).rev() {
|
||||||
|
if let Some(item) = chardevs.0.get(index) {
|
||||||
|
if item.is_empty() {
|
||||||
|
return Ok(index); // 返回可用的主设备号
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 寻找主设备号在384~511的设备
|
||||||
|
for index in (DEV_MAJOR_DYN_EXT_END + 1..DEV_MAJOR_DYN_EXT_START + 1).rev() {
|
||||||
|
if let Some(chardevss) = chardevs.0.get(Self::major_to_index(index)) {
|
||||||
|
let mut flag = true;
|
||||||
|
for item in chardevss {
|
||||||
|
if item.device_number().major() == index {
|
||||||
|
flag = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if flag {
|
||||||
|
// 如果数组中不存在主设备号等于index的设备
|
||||||
|
return Ok(index); // 返回可用的主设备号
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(SystemError::EBUSY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: 注册设备号,该函数需要指定主设备号
|
||||||
|
/// @parameter: from: 主设备号
|
||||||
|
/// count: 次设备号数量
|
||||||
|
/// name: 字符设备名
|
||||||
|
/// @return: 如果注册成功,返回设备号,否则,返回错误码
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn register_chardev_region(
|
||||||
|
from: DeviceNumber,
|
||||||
|
count: usize,
|
||||||
|
name: &'static str,
|
||||||
|
) -> Result<DeviceNumber, SystemError> {
|
||||||
|
Self::__register_chardev_region(from, count, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: 注册设备号,该函数自动分配主设备号
|
||||||
|
/// @parameter: baseminor: 次设备号
|
||||||
|
/// count: 次设备号数量
|
||||||
|
/// name: 字符设备名
|
||||||
|
/// @return: 如果注册成功,返回,否则,返回false
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn alloc_chardev_region(
|
||||||
|
baseminor: usize,
|
||||||
|
count: usize,
|
||||||
|
name: &'static str,
|
||||||
|
) -> Result<DeviceNumber, SystemError> {
|
||||||
|
Self::__register_chardev_region(mkdev(0, baseminor), count, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: 注册设备号
|
||||||
|
/// @parameter: device_number: 设备号,主设备号如果为0,则动态分配
|
||||||
|
/// minorct: 次设备号数量
|
||||||
|
/// name: 字符设备名
|
||||||
|
/// @return: 如果注册成功,返回设备号,否则,返回错误码
|
||||||
|
fn __register_chardev_region(
|
||||||
|
device_number: DeviceNumber,
|
||||||
|
minorct: usize,
|
||||||
|
name: &'static str,
|
||||||
|
) -> Result<DeviceNumber, SystemError> {
|
||||||
|
let mut major = device_number.major();
|
||||||
|
let baseminor = device_number.minor();
|
||||||
|
if major >= DEV_MAJOR_MAX {
|
||||||
|
kerror!(
|
||||||
|
"DEV {} major requested {} is greater than the maximum {}\n",
|
||||||
|
name,
|
||||||
|
major,
|
||||||
|
DEV_MAJOR_MAX - 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if minorct > MINOR_MASK + 1 - baseminor {
|
||||||
|
kerror!("DEV {} minor range requested ({}-{}) is out of range of maximum range ({}-{}) for a single major\n",
|
||||||
|
name, baseminor, baseminor + minorct - 1, 0, MINOR_MASK);
|
||||||
|
}
|
||||||
|
let chardev = DeviceStruct::new(mkdev(major, baseminor), minorct, name);
|
||||||
|
if major == 0 {
|
||||||
|
// 如果主设备号为0,则自动分配主设备号
|
||||||
|
major = Self::find_dynamic_major().expect("Find synamic major error.\n");
|
||||||
|
}
|
||||||
|
if let Some(items) = CHARDEVS.0.lock().0.get_mut(Self::major_to_index(major)) {
|
||||||
|
let mut insert_index: usize = 0;
|
||||||
|
for (index, item) in items.iter().enumerate() {
|
||||||
|
insert_index = index;
|
||||||
|
match item.device_number().major().cmp(&major) {
|
||||||
|
Ordering::Less => continue,
|
||||||
|
Ordering::Greater => {
|
||||||
|
break; // 大于则向后插入
|
||||||
|
}
|
||||||
|
Ordering::Equal => {
|
||||||
|
if item.device_number().minor() + item.minorct() <= baseminor {
|
||||||
|
continue; // 下一个主设备号大于或者次设备号大于被插入的次设备号最大值
|
||||||
|
}
|
||||||
|
if item.base_minor() >= baseminor + minorct {
|
||||||
|
break; // 在此处插入
|
||||||
|
}
|
||||||
|
return Err(SystemError::EBUSY); // 存在重合的次设备号
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items.insert(insert_index, chardev);
|
||||||
|
}
|
||||||
|
return Ok(mkdev(major, baseminor));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: 注销设备号
|
||||||
|
/// @parameter: major: 主设备号,如果为0,动态分配
|
||||||
|
/// baseminor: 起始次设备号
|
||||||
|
/// minorct: 次设备号数量
|
||||||
|
/// @return: 如果注销成功,返回(),否则,返回错误码
|
||||||
|
fn __unregister_chardev_region(
|
||||||
|
device_number: DeviceNumber,
|
||||||
|
minorct: usize,
|
||||||
|
) -> Result<(), SystemError> {
|
||||||
|
if let Some(items) = CHARDEVS
|
||||||
|
.0
|
||||||
|
.lock()
|
||||||
|
.0
|
||||||
|
.get_mut(Self::major_to_index(device_number.major()))
|
||||||
|
{
|
||||||
|
for (index, item) in items.iter().enumerate() {
|
||||||
|
if item.device_number() == device_number && item.minorct() == minorct {
|
||||||
|
// 设备号和数量都相等
|
||||||
|
items.remove(index);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Err(SystemError::EBUSY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: 字符设备注册
|
||||||
|
/// @parameter: cdev: 字符设备实例
|
||||||
|
/// dev_t: 字符设备号
|
||||||
|
/// range: 次设备号范围
|
||||||
|
/// @return: none
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn cdev_add(cdev: Arc<dyn CharDevice>, id_table: IdTable, range: usize) {
|
||||||
|
if Into::<usize>::into(id_table.device_number()) == 0 {
|
||||||
|
kerror!("Device number can't be 0!\n");
|
||||||
|
}
|
||||||
|
DEVICE_MANAGER.add_device(id_table.clone(), cdev.clone());
|
||||||
|
kobj_map(
|
||||||
|
DEVMAP.clone(),
|
||||||
|
id_table.device_number(),
|
||||||
|
range,
|
||||||
|
cdev.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief: 字符设备注销
|
||||||
|
/// @parameter: dev_t: 字符设备号
|
||||||
|
/// range: 次设备号范围
|
||||||
|
/// @return: none
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn cdev_del(id_table: IdTable, range: usize) {
|
||||||
|
DEVICE_MANAGER.remove_device(&id_table);
|
||||||
|
kobj_unmap(DEVMAP.clone(), id_table.device_number(), range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
pub mod block;
|
||||||
pub mod char;
|
pub mod char;
|
||||||
pub mod device;
|
pub mod device;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
use super::device::{
|
use super::device::{
|
||||||
bus::{bus_driver_register, bus_register, Bus, BusDriver, BusState},
|
bus::{bus_driver_register, bus_register, Bus, BusDriver, BusState},
|
||||||
driver::Driver,
|
driver::DriverError,
|
||||||
Device, DeviceError, DeviceState, DeviceType, IdTable, KObject,
|
Device, DeviceError, DeviceNumber, DevicePrivateData, DeviceResource, DeviceType, IdTable,
|
||||||
|
KObject,
|
||||||
|
};
|
||||||
|
use crate::{
|
||||||
|
driver::Driver, filesystem::vfs::IndexNode, libs::spinlock::SpinLock, syscall::SystemError,
|
||||||
};
|
};
|
||||||
use crate::{filesystem::vfs::IndexNode, libs::spinlock::SpinLock, syscall::SystemError};
|
|
||||||
use alloc::{
|
use alloc::{
|
||||||
collections::{BTreeMap, BTreeSet},
|
collections::{BTreeMap, BTreeSet},
|
||||||
|
string::ToString,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
@ -19,7 +23,7 @@ pub mod platform_driver;
|
|||||||
/// @brief: platform总线匹配表
|
/// @brief: platform总线匹配表
|
||||||
/// 总线上的设备和驱动都存在一份匹配表
|
/// 总线上的设备和驱动都存在一份匹配表
|
||||||
/// 根据匹配表条目是否匹配来辨识设备和驱动能否进行匹配
|
/// 根据匹配表条目是否匹配来辨识设备和驱动能否进行匹配
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CompatibleTable(BTreeSet<&'static str>);
|
pub struct CompatibleTable(BTreeSet<&'static str>);
|
||||||
|
|
||||||
/// @brief: 匹配表操作方法集
|
/// @brief: 匹配表操作方法集
|
||||||
@ -38,12 +42,16 @@ impl CompatibleTable {
|
|||||||
/// @return: 如果匹配成功,返回true,否则,返回false
|
/// @return: 如果匹配成功,返回true,否则,返回false
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn matches(&self, other: &CompatibleTable) -> bool {
|
pub fn matches(&self, other: &CompatibleTable) -> bool {
|
||||||
for id in &self.0 {
|
self.0.intersection(&other.0).next().is_some()
|
||||||
if other.0.contains(id) {
|
}
|
||||||
return true;
|
|
||||||
}
|
/// @brief: 添加一组匹配条目
|
||||||
|
/// @param:
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn add_device(&mut self, devices: Vec<&'static str>) {
|
||||||
|
for str in devices {
|
||||||
|
self.0.insert(str);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,9 +119,13 @@ impl LockedPlatformBusDriver {
|
|||||||
/// @return: None
|
/// @return: None
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[inline]
|
#[inline]
|
||||||
fn unregister_platform_driver(&mut self, driver: Arc<dyn PlatformDriver>) {
|
fn unregister_platform_driver(
|
||||||
|
&mut self,
|
||||||
|
driver: Arc<dyn PlatformDriver>,
|
||||||
|
) -> Result<(), DeviceError> {
|
||||||
let id_table = driver.id_table();
|
let id_table = driver.id_table();
|
||||||
self.0.lock().drivers.remove(&id_table);
|
self.0.lock().drivers.remove(&id_table);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief: 注册platform类型设备
|
/// @brief: 注册platform类型设备
|
||||||
@ -144,63 +156,6 @@ impl LockedPlatformBusDriver {
|
|||||||
let id_table = device.id_table();
|
let id_table = device.id_table();
|
||||||
self.0.lock().devices.remove(&id_table);
|
self.0.lock().devices.remove(&id_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief: 匹配platform类型驱动
|
|
||||||
/// @parameter driver: platform类型驱动
|
|
||||||
/// @return: 如果匹配成功,返回成功驱动的设备数,否则,返回BusError类型
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn driver_match_device(&self, driver: Arc<dyn PlatformDriver>) -> Result<i32, DeviceError> {
|
|
||||||
let mut num = 0;
|
|
||||||
let devices = &self.0.lock().devices;
|
|
||||||
|
|
||||||
for (_dev_id_table, device) in devices.iter() {
|
|
||||||
if device
|
|
||||||
.compatible_table()
|
|
||||||
.matches(&driver.compatible_table())
|
|
||||||
{
|
|
||||||
if !device.is_initialized() {
|
|
||||||
// 设备未初始化,调用驱动probe函数
|
|
||||||
match driver.probe(device.clone()) {
|
|
||||||
Ok(()) => {
|
|
||||||
num = num + 1;
|
|
||||||
device.set_state(DeviceState::Initialized)
|
|
||||||
}
|
|
||||||
// 可以驱动很多设备,一个设备初始化出错即返回
|
|
||||||
Err(_) => return Err(DeviceError::InitializeFailed),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if num == 0 {
|
|
||||||
return Err(DeviceError::NoDeviceForDriver);
|
|
||||||
} else {
|
|
||||||
return Ok(num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief: 匹配platform上的设备
|
|
||||||
/// @parameter driver: platform类型设备
|
|
||||||
/// @return: 如果匹配成功,返回Ok(()),否则,返回BusError类型
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn device_match_driver(&self, device: Arc<dyn PlatformDevice>) -> Result<(), DeviceError> {
|
|
||||||
let drivers = &mut self.0.lock().drivers;
|
|
||||||
for (_drv_id_table, driver) in drivers.into_iter() {
|
|
||||||
if driver
|
|
||||||
.compatible_table()
|
|
||||||
.matches(&device.compatible_table())
|
|
||||||
{
|
|
||||||
match driver.probe(device.clone()) {
|
|
||||||
Ok(_driver) => {
|
|
||||||
// 将设备状态置为已初始化
|
|
||||||
device.set_state(DeviceState::Initialized);
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
Err(_) => return Err(DeviceError::InitializeFailed),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Err(DeviceError::NoDriverForDevice);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief: platform总线驱动
|
/// @brief: platform总线驱动
|
||||||
@ -235,7 +190,7 @@ impl Driver for LockedPlatformBusDriver {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn id_table(&self) -> IdTable {
|
fn id_table(&self) -> IdTable {
|
||||||
IdTable::new("PlatformBusDriver", 0)
|
return IdTable::new("PlatformBusDriver".to_string(), DeviceNumber::new(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -249,6 +204,18 @@ impl Driver for LockedPlatformBusDriver {
|
|||||||
fn set_sys_info(&self, sys_info: Option<Arc<dyn IndexNode>>) {
|
fn set_sys_info(&self, sys_info: Option<Arc<dyn IndexNode>>) {
|
||||||
self.0.lock().sys_info = sys_info;
|
self.0.lock().sys_info = sys_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn probe(&self, _data: &DevicePrivateData) -> Result<(), DriverError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load(
|
||||||
|
&self,
|
||||||
|
_data: DevicePrivateData,
|
||||||
|
_resource: Option<DeviceResource>,
|
||||||
|
) -> Result<Arc<dyn Device>, DriverError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief: 为PlatformBusDriver实现BusDriver trait
|
/// @brief: 为PlatformBusDriver实现BusDriver trait
|
||||||
@ -271,8 +238,8 @@ impl LockedPlatform {
|
|||||||
/// @brief: 创建一个加锁的platform总线实例
|
/// @brief: 创建一个加锁的platform总线实例
|
||||||
/// @parameter: None
|
/// @parameter: None
|
||||||
/// @return: platform总线实例
|
/// @return: platform总线实例
|
||||||
pub fn new() -> LockedPlatform {
|
pub fn new(data: DevicePrivateData) -> LockedPlatform {
|
||||||
LockedPlatform(SpinLock::new(Platform::new()))
|
LockedPlatform(SpinLock::new(Platform::new(data)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief: 获取总线的匹配表
|
/// @brief: 获取总线的匹配表
|
||||||
@ -316,22 +283,22 @@ impl LockedPlatform {
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief:
|
// /// @brief:
|
||||||
/// @parameter: None
|
// /// @parameter: None
|
||||||
/// @return: 总线状态
|
// /// @return: 总线状态
|
||||||
#[inline]
|
// #[inline]
|
||||||
#[allow(dead_code)]
|
// #[allow(dead_code)]
|
||||||
fn set_driver(&self, driver: Option<Arc<LockedPlatformBusDriver>>) {
|
// fn set_driver(&self, driver: Option<Arc<LockedPlatformBusDriver>>) {
|
||||||
self.0.lock().driver = driver;
|
// self.0.lock().driver = driver;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief: platform总线
|
/// @brief: platform总线
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Platform {
|
pub struct Platform {
|
||||||
state: BusState, // 总线状态
|
_data: DevicePrivateData,
|
||||||
driver: Option<Arc<LockedPlatformBusDriver>>, // 总线驱动
|
state: BusState, // 总线状态
|
||||||
sys_info: Option<Arc<dyn IndexNode>>, // 总线sys information
|
sys_info: Option<Arc<dyn IndexNode>>, // 总线sys information
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief: platform方法集
|
/// @brief: platform方法集
|
||||||
@ -339,10 +306,10 @@ impl Platform {
|
|||||||
/// @brief: 创建一个platform总线实例
|
/// @brief: 创建一个platform总线实例
|
||||||
/// @parameter: None
|
/// @parameter: None
|
||||||
/// @return: platform总线实例
|
/// @return: platform总线实例
|
||||||
pub fn new() -> Self {
|
pub fn new(_data: DevicePrivateData) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
_data,
|
||||||
state: BusState::NotInitialized,
|
state: BusState::NotInitialized,
|
||||||
driver: Option::None,
|
|
||||||
sys_info: Option::None,
|
sys_info: Option::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -359,7 +326,7 @@ impl Device for LockedPlatform {
|
|||||||
#[inline]
|
#[inline]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn id_table(&self) -> IdTable {
|
fn id_table(&self) -> IdTable {
|
||||||
IdTable::new("platform", 0)
|
IdTable::new("platform".to_string(), DeviceNumber::new(0))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -373,7 +340,7 @@ impl Device for LockedPlatform {
|
|||||||
return self.0.lock().sys_info.clone();
|
return self.0.lock().sys_info.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_any_ref(&'static self) -> &'static dyn core::any::Any {
|
fn as_any_ref(&self) -> &dyn core::any::Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -388,10 +355,16 @@ impl KObject for LockedPlatform {}
|
|||||||
/// @return: None
|
/// @return: None
|
||||||
pub fn platform_bus_init() -> Result<(), SystemError> {
|
pub fn platform_bus_init() -> Result<(), SystemError> {
|
||||||
let platform_driver: Arc<LockedPlatformBusDriver> = Arc::new(LockedPlatformBusDriver::new());
|
let platform_driver: Arc<LockedPlatformBusDriver> = Arc::new(LockedPlatformBusDriver::new());
|
||||||
let platform_device: Arc<LockedPlatform> = Arc::new(LockedPlatform::new());
|
let platform_device: Arc<LockedPlatform> =
|
||||||
|
Arc::new(LockedPlatform::new(DevicePrivateData::new(
|
||||||
|
IdTable::new("platform".to_string(), DeviceNumber::new(0)),
|
||||||
|
None,
|
||||||
|
CompatibleTable::new(vec!["platform"]),
|
||||||
|
BusState::NotInitialized.into(),
|
||||||
|
)));
|
||||||
bus_register(platform_device.clone()).map_err(|e| e.into())?;
|
bus_register(platform_device.clone()).map_err(|e| e.into())?;
|
||||||
platform_device.set_state(BusState::Initialized);
|
platform_device.set_state(BusState::Initialized);
|
||||||
platform_device.set_driver(Some(platform_driver.clone()));
|
//platform_device.set_driver(Some(platform_driver.clone()));
|
||||||
bus_driver_register(platform_driver.clone()).map_err(|e| e.into())?;
|
bus_driver_register(platform_driver.clone()).map_err(|e| e.into())?;
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -1,18 +1,11 @@
|
|||||||
use super::{
|
use crate::driver::base::device::Device;
|
||||||
super::device::{Device, DeviceState},
|
|
||||||
platform_driver::PlatformDriver,
|
use super::{super::device::DeviceState, CompatibleTable};
|
||||||
CompatibleTable,
|
|
||||||
};
|
|
||||||
use alloc::sync::Arc;
|
|
||||||
|
|
||||||
/// @brief: 实现该trait的设备实例应挂载在platform总线上,
|
/// @brief: 实现该trait的设备实例应挂载在platform总线上,
|
||||||
/// 同时应该实现Device trait
|
/// 同时应该实现Device trait
|
||||||
pub trait PlatformDevice: Device {
|
pub trait PlatformDevice: Device {
|
||||||
/// @brief: 获取设备匹配表
|
|
||||||
/// @parameter: None
|
|
||||||
/// @return: 设备匹配表
|
|
||||||
fn compatible_table(&self) -> CompatibleTable;
|
fn compatible_table(&self) -> CompatibleTable;
|
||||||
|
|
||||||
/// @brief: 判断设备是否初始化
|
/// @brief: 判断设备是否初始化
|
||||||
/// @parameter: None
|
/// @parameter: None
|
||||||
/// @return: 如果已经初始化,返回true,否则,返回false
|
/// @return: 如果已经初始化,返回true,否则,返回false
|
||||||
@ -22,9 +15,4 @@ pub trait PlatformDevice: Device {
|
|||||||
/// @parameter set_state: 设备状态
|
/// @parameter set_state: 设备状态
|
||||||
/// @return: None
|
/// @return: None
|
||||||
fn set_state(&self, set_state: DeviceState);
|
fn set_state(&self, set_state: DeviceState);
|
||||||
|
|
||||||
/// @brief: 设置platform设备驱动
|
|
||||||
/// @parameter driver: platform设备驱动
|
|
||||||
/// @return: None
|
|
||||||
fn set_driver(&self, driver: Option<Arc<dyn PlatformDriver>>);
|
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
use super::{
|
use crate::driver::{base::device::DevicePrivateData, Driver};
|
||||||
super::device::driver::{Driver, DriverError},
|
|
||||||
platform_device::PlatformDevice,
|
|
||||||
CompatibleTable,
|
|
||||||
};
|
|
||||||
use alloc::sync::Arc;
|
|
||||||
|
|
||||||
|
use super::{super::device::driver::DriverError, CompatibleTable};
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref PLATFORM_COMPAT_TABLE: CompatibleTable = CompatibleTable::new(vec!["platform"]);
|
||||||
|
}
|
||||||
/// @brief: 实现该trait的设备驱动实例应挂载在platform总线上,
|
/// @brief: 实现该trait的设备驱动实例应挂载在platform总线上,
|
||||||
/// 同时应该实现Driver trait
|
/// 同时应该实现Driver trait
|
||||||
pub trait PlatformDriver: Driver {
|
pub trait PlatformDriver: Driver {
|
||||||
/// @brief: 设备驱动探测函数,此函数在设备和驱动匹配成功后调用
|
|
||||||
/// @parameter device: 匹配成功的设备实例
|
|
||||||
/// @return: 成功驱动设备,返回Ok(()),否则,返回DriverError
|
|
||||||
fn probe(&self, device: Arc<dyn PlatformDevice>) -> Result<(), DriverError>;
|
|
||||||
|
|
||||||
/// @brief: 获取驱动匹配表
|
|
||||||
/// @parameter: None
|
|
||||||
/// @return: 驱动匹配表
|
|
||||||
fn compatible_table(&self) -> CompatibleTable;
|
fn compatible_table(&self) -> CompatibleTable;
|
||||||
|
/// @brief 探测设备
|
||||||
|
/// @param data 设备初始拥有的基本信息
|
||||||
|
fn probe(&self, data: DevicePrivateData) -> Result<(), DriverError> {
|
||||||
|
if data.compatible_table().matches(&PLATFORM_COMPAT_TABLE) {
|
||||||
|
return Ok(());
|
||||||
|
} else {
|
||||||
|
return Err(DriverError::UnsupportedOperation);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
use crate::driver::base::block::block_device::BlockDevice;
|
||||||
use crate::filesystem::devfs::{DevFS, DeviceINode};
|
use crate::filesystem::devfs::{DevFS, DeviceINode};
|
||||||
use crate::filesystem::vfs::file::FileMode;
|
use crate::filesystem::vfs::file::FileMode;
|
||||||
use crate::filesystem::vfs::io::device::BlockDevice;
|
|
||||||
use crate::filesystem::vfs::{
|
use crate::filesystem::vfs::{
|
||||||
core::generate_inode_id, make_rawdev, FilePrivateData, FileSystem, FileType, IndexNode,
|
core::generate_inode_id, make_rawdev, FilePrivateData, FileSystem, FileType, IndexNode,
|
||||||
Metadata, PollStatus,
|
Metadata, PollStatus,
|
||||||
@ -124,7 +124,7 @@ impl IndexNode for LockedAhciInode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let FilePrivateData::Unused = data {
|
if let FilePrivateData::Unused = data {
|
||||||
return self.0.lock().disk.read_at(offset, len, buf);
|
return self.0.lock().disk.read_at_bytes(offset, len, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(SystemError::EINVAL);
|
return Err(SystemError::EINVAL);
|
||||||
@ -143,7 +143,7 @@ impl IndexNode for LockedAhciInode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let FilePrivateData::Unused = data {
|
if let FilePrivateData::Unused = data {
|
||||||
return self.0.lock().disk.write_at(offset, len, buf);
|
return self.0.lock().disk.write_at_bytes(offset, len, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Err(SystemError::EINVAL);
|
return Err(SystemError::EINVAL);
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
use super::{_port, hba::HbaCmdTable, virt_2_phys};
|
use super::{_port, hba::HbaCmdTable, virt_2_phys};
|
||||||
|
use crate::driver::base::block::block_device::{BlockDevice, BlockId};
|
||||||
|
use crate::driver::base::block::disk_info::Partition;
|
||||||
|
use crate::driver::base::block::SeekFrom;
|
||||||
|
use crate::driver::base::device::{Device, DeviceType, KObject};
|
||||||
use crate::driver::disk::ahci::HBA_PxIS_TFES;
|
use crate::driver::disk::ahci::HBA_PxIS_TFES;
|
||||||
use crate::filesystem::mbr::MbrDiskPartionTable;
|
use crate::filesystem::mbr::MbrDiskPartionTable;
|
||||||
use crate::filesystem::vfs::io::{device::BlockDevice, disk_info::Partition, SeekFrom};
|
|
||||||
use crate::include::bindings::bindings::verify_area;
|
use crate::include::bindings::bindings::verify_area;
|
||||||
|
|
||||||
|
use crate::kdebug;
|
||||||
use crate::libs::{spinlock::SpinLock, vec_cursor::VecCursor};
|
use crate::libs::{spinlock::SpinLock, vec_cursor::VecCursor};
|
||||||
use crate::mm::phys_2_virt;
|
use crate::mm::phys_2_virt;
|
||||||
use crate::syscall::SystemError;
|
use crate::syscall::SystemError;
|
||||||
@ -52,8 +56,8 @@ impl Debug for AhciDisk {
|
|||||||
impl AhciDisk {
|
impl AhciDisk {
|
||||||
fn read_at(
|
fn read_at(
|
||||||
&self,
|
&self,
|
||||||
lba_id_start: crate::filesystem::vfs::io::device::BlockId, // 起始lba编号
|
lba_id_start: BlockId, // 起始lba编号
|
||||||
count: usize, // 读取lba的数量
|
count: usize, // 读取lba的数量
|
||||||
buf: &mut [u8],
|
buf: &mut [u8],
|
||||||
) -> Result<usize, SystemError> {
|
) -> Result<usize, SystemError> {
|
||||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||||
@ -211,7 +215,7 @@ impl AhciDisk {
|
|||||||
|
|
||||||
fn write_at(
|
fn write_at(
|
||||||
&self,
|
&self,
|
||||||
lba_id_start: crate::filesystem::vfs::io::device::BlockId,
|
lba_id_start: BlockId,
|
||||||
count: usize,
|
count: usize,
|
||||||
buf: &[u8],
|
buf: &[u8],
|
||||||
) -> Result<usize, SystemError> {
|
) -> Result<usize, SystemError> {
|
||||||
@ -392,7 +396,6 @@ impl LockedAhciDisk {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.0.lock().partitions = part_s;
|
result.0.lock().partitions = part_s;
|
||||||
result.0.lock().self_ref = weak_this;
|
result.0.lock().self_ref = weak_this;
|
||||||
return Ok(result);
|
return Ok(result);
|
||||||
@ -406,14 +409,13 @@ impl LockedAhciDisk {
|
|||||||
let mut buf: Vec<u8> = Vec::new();
|
let mut buf: Vec<u8> = Vec::new();
|
||||||
buf.resize(size_of::<MbrDiskPartionTable>(), 0);
|
buf.resize(size_of::<MbrDiskPartionTable>(), 0);
|
||||||
|
|
||||||
self.read_at(0, 1, &mut buf)?;
|
BlockDevice::read_at(self, 0, 1, &mut buf)?;
|
||||||
|
|
||||||
// 创建 Cursor 用于按字节读取
|
// 创建 Cursor 用于按字节读取
|
||||||
let mut cursor = VecCursor::new(buf);
|
let mut cursor = VecCursor::new(buf);
|
||||||
cursor.seek(SeekFrom::SeekCurrent(446))?;
|
cursor.seek(SeekFrom::SeekCurrent(446))?;
|
||||||
|
|
||||||
for i in 0..4 {
|
for i in 0..4 {
|
||||||
// kdebug!("infomation of partition {}:\n", i);
|
kdebug!("infomation of partition {}:\n", i);
|
||||||
|
|
||||||
table.dpte[i].flags = cursor.read_u8()?;
|
table.dpte[i].flags = cursor.read_u8()?;
|
||||||
table.dpte[i].starting_head = cursor.read_u8()?;
|
table.dpte[i].starting_head = cursor.read_u8()?;
|
||||||
@ -424,7 +426,7 @@ impl LockedAhciDisk {
|
|||||||
table.dpte[i].starting_lba = cursor.read_u32()?;
|
table.dpte[i].starting_lba = cursor.read_u32()?;
|
||||||
table.dpte[i].total_sectors = cursor.read_u32()?;
|
table.dpte[i].total_sectors = cursor.read_u32()?;
|
||||||
|
|
||||||
// kdebug!("dpte[i] = {:?}", table.dpte[i]);
|
kdebug!("dpte[i] = {:?}", table.dpte[i]);
|
||||||
}
|
}
|
||||||
table.bs_trailsig = cursor.read_u16()?;
|
table.bs_trailsig = cursor.read_u16()?;
|
||||||
// kdebug!("bs_trailsig = {}", unsafe {
|
// kdebug!("bs_trailsig = {}", unsafe {
|
||||||
@ -435,6 +437,30 @@ impl LockedAhciDisk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl KObject for LockedAhciDisk {}
|
||||||
|
|
||||||
|
impl Device for LockedAhciDisk {
|
||||||
|
fn dev_type(&self) -> DeviceType {
|
||||||
|
return DeviceType::Block;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_ref(&self) -> &dyn core::any::Any {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn id_table(&self) -> crate::driver::base::device::IdTable {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_sys_info(&self, _sys_info: Option<Arc<dyn crate::filesystem::vfs::IndexNode>>) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sys_info(&self) -> Option<Arc<dyn crate::filesystem::vfs::IndexNode>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl BlockDevice for LockedAhciDisk {
|
impl BlockDevice for LockedAhciDisk {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_any_ref(&self) -> &dyn core::any::Any {
|
fn as_any_ref(&self) -> &dyn core::any::Any {
|
||||||
@ -446,36 +472,12 @@ impl BlockDevice for LockedAhciDisk {
|
|||||||
9
|
9
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn read_at(
|
|
||||||
&self,
|
|
||||||
lba_id_start: crate::filesystem::vfs::io::device::BlockId,
|
|
||||||
count: usize,
|
|
||||||
buf: &mut [u8],
|
|
||||||
) -> Result<usize, SystemError> {
|
|
||||||
// kdebug!(
|
|
||||||
// "ahci read at {lba_id_start}, count={count}, lock={:?}",
|
|
||||||
// self.0
|
|
||||||
// );
|
|
||||||
return self.0.lock().read_at(lba_id_start, count, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn write_at(
|
|
||||||
&self,
|
|
||||||
lba_id_start: crate::filesystem::vfs::io::device::BlockId,
|
|
||||||
count: usize,
|
|
||||||
buf: &[u8],
|
|
||||||
) -> Result<usize, SystemError> {
|
|
||||||
self.0.lock().write_at(lba_id_start, count, buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sync(&self) -> Result<(), SystemError> {
|
fn sync(&self) -> Result<(), SystemError> {
|
||||||
return self.0.lock().sync();
|
return self.0.lock().sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn device(&self) -> Arc<dyn crate::filesystem::vfs::io::device::Device> {
|
fn device(&self) -> Arc<dyn Device> {
|
||||||
return self.0.lock().self_ref.upgrade().unwrap();
|
return self.0.lock().self_ref.upgrade().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,4 +488,24 @@ impl BlockDevice for LockedAhciDisk {
|
|||||||
fn partitions(&self) -> Vec<Arc<Partition>> {
|
fn partitions(&self) -> Vec<Arc<Partition>> {
|
||||||
return self.0.lock().partitions.clone();
|
return self.0.lock().partitions.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn read_at(
|
||||||
|
&self,
|
||||||
|
lba_id_start: BlockId, // 起始lba编号
|
||||||
|
count: usize, // 读取lba的数量
|
||||||
|
buf: &mut [u8],
|
||||||
|
) -> Result<usize, SystemError> {
|
||||||
|
self.0.lock().read_at(lba_id_start, count, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn write_at(
|
||||||
|
&self,
|
||||||
|
lba_id_start: BlockId,
|
||||||
|
count: usize,
|
||||||
|
buf: &[u8],
|
||||||
|
) -> Result<usize, SystemError> {
|
||||||
|
self.0.lock().write_at(lba_id_start, count, buf)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,13 @@ pub mod ahci_inode;
|
|||||||
pub mod ahcidisk;
|
pub mod ahcidisk;
|
||||||
pub mod hba;
|
pub mod hba;
|
||||||
|
|
||||||
use crate::filesystem::vfs::io::device::BlockDevice;
|
use crate::driver::base::block::block_device::BlockDevice;
|
||||||
|
use crate::driver::base::block::disk_info::BLK_GF_AHCI;
|
||||||
// 依赖的rust工具包
|
// 依赖的rust工具包
|
||||||
use crate::driver::pci::pci::{
|
use crate::driver::pci::pci::{
|
||||||
get_pci_device_structure_mut, PciDeviceStructure, PCI_DEVICE_LINKEDLIST,
|
get_pci_device_structure_mut, PciDeviceStructure, PCI_DEVICE_LINKEDLIST,
|
||||||
};
|
};
|
||||||
use crate::filesystem::devfs::devfs_register;
|
use crate::filesystem::devfs::devfs_register;
|
||||||
use crate::filesystem::vfs::io::disk_info::BLK_GF_AHCI;
|
|
||||||
use crate::kerror;
|
use crate::kerror;
|
||||||
use crate::libs::rwlock::RwLockWriteGuard;
|
use crate::libs::rwlock::RwLockWriteGuard;
|
||||||
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
|
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
#include "ata.h"
|
|
||||||
#include <common/kprint.h>
|
|
||||||
#include <driver/interrupt/apic/apic.h>
|
|
||||||
|
|
||||||
struct apic_IO_APIC_RTE_entry entry;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 硬盘中断上半部处理程序
|
|
||||||
*
|
|
||||||
* @param irq_num
|
|
||||||
* @param param
|
|
||||||
* @param regs
|
|
||||||
*/
|
|
||||||
void ata_disk_handler(ul irq_num, ul param, struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
struct ata_identify_device_data info;
|
|
||||||
|
|
||||||
kdebug("irq_num=%ld", irq_num);
|
|
||||||
|
|
||||||
// 从端口读入磁盘配置信息
|
|
||||||
io_insw(PORT_DISK0_DATA, &info, 256);
|
|
||||||
kdebug("General_Config=%#018lx", info.General_Config);
|
|
||||||
printk("Serial number:");
|
|
||||||
unsigned char buf[64];
|
|
||||||
int js=0;
|
|
||||||
//printk("%d", info.Serial_Number);
|
|
||||||
|
|
||||||
for(int i = 0;i<10;i++)
|
|
||||||
{
|
|
||||||
buf[js++]=(info.Serial_Number[i] & 0xff);
|
|
||||||
}
|
|
||||||
buf[js] = '\0';
|
|
||||||
printk("%s", buf);
|
|
||||||
printk("\n");
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
hardware_intr_controller ata_disk_intr_controller =
|
|
||||||
{
|
|
||||||
.enable = apic_ioapic_enable,
|
|
||||||
.disable = apic_ioapic_disable,
|
|
||||||
.install = apic_ioapic_install,
|
|
||||||
.uninstall = apic_ioapic_uninstall,
|
|
||||||
.ack = apic_ioapic_edge_ack,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 初始化ATA磁盘驱动程序
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
void ata_init()
|
|
||||||
{
|
|
||||||
entry.vector = 0x2e;
|
|
||||||
entry.deliver_mode = IO_APIC_FIXED;
|
|
||||||
entry.dest_mode = DEST_PHYSICAL;
|
|
||||||
entry.deliver_status = IDLE;
|
|
||||||
entry.polarity = POLARITY_HIGH;
|
|
||||||
entry.remote_IRR = IRR_RESET;
|
|
||||||
entry.trigger_mode = EDGE_TRIGGER;
|
|
||||||
entry.mask = MASKED;
|
|
||||||
entry.reserved = 0;
|
|
||||||
|
|
||||||
entry.destination.physical.reserved1 = 0;
|
|
||||||
entry.destination.physical.reserved2 = 0;
|
|
||||||
entry.destination.physical.phy_dest = 0; // 投递至BSP
|
|
||||||
|
|
||||||
irq_register(entry.vector, &entry, &ata_disk_handler, 0, &ata_disk_intr_controller, "ATA Disk 1");
|
|
||||||
|
|
||||||
io_out8(PORT_DISK0_STATUS_CTRL_REG, 0); // 使能中断请求
|
|
||||||
|
|
||||||
io_out8(PORT_DISK0_ERR_STATUS, 0);
|
|
||||||
io_out8(PORT_DISK0_SECTOR_CNT, 0);
|
|
||||||
io_out8(PORT_DISK0_LBA_7_0, 0);
|
|
||||||
io_out8(PORT_DISK0_LBA_15_8, 0);
|
|
||||||
io_out8(PORT_DISK0_LBA_23_16, 0);
|
|
||||||
io_out8(PORT_DISK0_DEVICE_CONFIGURE_REG, 0);
|
|
||||||
|
|
||||||
io_out8(PORT_DISK0_CONTROLLER_STATUS_CMD, 0xec); // 获取硬件设备识别信息
|
|
||||||
}
|
|
@ -11,6 +11,60 @@ pub mod video;
|
|||||||
pub mod virtio;
|
pub mod virtio;
|
||||||
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
|
||||||
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
|
use crate::filesystem::vfs::IndexNode;
|
||||||
|
|
||||||
|
use self::base::{
|
||||||
|
device::{driver::DriverError, Device, DevicePrivateData, DeviceResource, IdTable},
|
||||||
|
platform::CompatibleTable,
|
||||||
|
};
|
||||||
pub trait Driver: Sync + Send + Debug {
|
pub trait Driver: Sync + Send + Debug {
|
||||||
fn as_any_ref(&'static self) -> &'static dyn core::any::Any;
|
fn as_any_ref(&'static self) -> &'static dyn core::any::Any;
|
||||||
|
|
||||||
|
//对于不需要匹配,在系统初始化的时候就生成的设备,例如 PlatformBus 就不需要匹配表
|
||||||
|
|
||||||
|
/// @brief: 获取驱动匹配表
|
||||||
|
/// @parameter: None
|
||||||
|
/// @return: 驱动匹配表
|
||||||
|
fn compatible_table(&self) -> CompatibleTable {
|
||||||
|
//TODO 要完善每个 CompatibleTable ,将来要把这个默认实现删除
|
||||||
|
return CompatibleTable::new(vec!["unknown"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 添加可支持的设备
|
||||||
|
/// @parameter: device 新增的匹配项
|
||||||
|
fn append_compatible_table(&self, _device: &CompatibleTable) -> Result<(), DriverError> {
|
||||||
|
Err(DriverError::UnsupportedOperation)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @brief 探测设备
|
||||||
|
/// @param data 设备初始拥有的基本信息
|
||||||
|
fn probe(&self, data: &DevicePrivateData) -> Result<(), DriverError>;
|
||||||
|
|
||||||
|
/// @brief 加载设备,包括检查资源可用性,和注册到相应的管理器中。
|
||||||
|
/// @param data 设备初始拥有的信息
|
||||||
|
/// @param resource 设备可能申请的资源(或者像伪设备不需要就为None)
|
||||||
|
fn load(
|
||||||
|
&self,
|
||||||
|
data: DevicePrivateData,
|
||||||
|
resource: Option<DeviceResource>,
|
||||||
|
) -> Result<Arc<dyn Device>, DriverError>;
|
||||||
|
|
||||||
|
/// @brief: 获取驱动标识符
|
||||||
|
/// @parameter: None
|
||||||
|
/// @return: 该驱动驱动唯一标识符
|
||||||
|
fn id_table(&self) -> IdTable;
|
||||||
|
|
||||||
|
// 考虑到很多驱动并不需要存储在系统中,只需要当工具人就可以了,因此 SysINode 是可选的
|
||||||
|
/// @brief: 设置驱动的sys information
|
||||||
|
/// @parameter id_table: 驱动标识符,用于唯一标识该驱动
|
||||||
|
/// @return: 驱动实例
|
||||||
|
fn set_sys_info(&self, sys_info: Option<Arc<dyn IndexNode>>);
|
||||||
|
|
||||||
|
/// @brief: 获取驱动的sys information
|
||||||
|
/// @parameter id_table: 驱动标识符,用于唯一标识该驱动
|
||||||
|
/// @return: 驱动实例
|
||||||
|
fn sys_info(&self) -> Option<Arc<dyn IndexNode>>;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,11 @@ use smoltcp::{phy, wire};
|
|||||||
use virtio_drivers::{device::net::VirtIONet, transport::Transport};
|
use virtio_drivers::{device::net::VirtIONet, transport::Transport};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
driver::{virtio::virtio_impl::HalImpl, Driver},
|
driver::{
|
||||||
|
base::device::{driver::DriverError, Device, DevicePrivateData, DeviceResource, IdTable},
|
||||||
|
virtio::virtio_impl::HalImpl,
|
||||||
|
Driver,
|
||||||
|
},
|
||||||
kerror, kinfo,
|
kerror, kinfo,
|
||||||
libs::spinlock::SpinLock,
|
libs::spinlock::SpinLock,
|
||||||
net::{generate_iface_id, NET_DRIVERS},
|
net::{generate_iface_id, NET_DRIVERS},
|
||||||
@ -240,6 +244,30 @@ impl<T: Transport> Driver for VirtioInterface<T> {
|
|||||||
fn as_any_ref(&'static self) -> &'static dyn core::any::Any {
|
fn as_any_ref(&'static self) -> &'static dyn core::any::Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn probe(&self, _data: &DevicePrivateData) -> Result<(), DriverError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load(
|
||||||
|
&self,
|
||||||
|
_data: DevicePrivateData,
|
||||||
|
_resource: Option<DeviceResource>,
|
||||||
|
) -> Result<Arc<dyn Device>, DriverError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn id_table(&self) -> IdTable {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_sys_info(&self, _sys_info: Option<Arc<dyn crate::filesystem::vfs::IndexNode>>) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sys_info(&self) -> Option<Arc<dyn crate::filesystem::vfs::IndexNode>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Transport> NetDriver for VirtioInterface<T> {
|
impl<T: Transport> NetDriver for VirtioInterface<T> {
|
||||||
|
@ -1 +1,2 @@
|
|||||||
pub mod uart;
|
pub mod uart_device;
|
||||||
|
pub mod uart_driver;
|
||||||
|
@ -1,22 +1,38 @@
|
|||||||
use super::super::base::device::Device;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
driver::base::{
|
driver::{
|
||||||
char::CharDevice,
|
base::{
|
||||||
device::{driver::Driver, DeviceState, DeviceType, IdTable, KObject},
|
char::CharDevice,
|
||||||
platform::{
|
device::{
|
||||||
self, platform_device::PlatformDevice, platform_driver::PlatformDriver, CompatibleTable,
|
driver::DriverError, Device, DeviceError, DeviceNumber, DevicePrivateData,
|
||||||
|
DeviceResource, DeviceState, DeviceType, IdTable, KObject, DEVICE_MANAGER,
|
||||||
|
},
|
||||||
|
platform::{
|
||||||
|
platform_device::PlatformDevice, platform_driver::PlatformDriver, CompatibleTable,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
Driver,
|
||||||
},
|
},
|
||||||
filesystem::{
|
filesystem::{
|
||||||
|
devfs::{devfs_register, DevFS, DeviceINode},
|
||||||
sysfs::bus::{bus_device_register, bus_driver_register},
|
sysfs::bus::{bus_device_register, bus_driver_register},
|
||||||
vfs::IndexNode,
|
vfs::{FilePrivateData, FileSystem, FileType, IndexNode, Metadata, PollStatus},
|
||||||
},
|
},
|
||||||
include::bindings::bindings::{io_in8, io_out8},
|
include::bindings::bindings::{io_in8, io_out8},
|
||||||
|
kinfo,
|
||||||
libs::spinlock::SpinLock,
|
libs::spinlock::SpinLock,
|
||||||
syscall::SystemError,
|
syscall::SystemError,
|
||||||
};
|
};
|
||||||
use alloc::sync::Arc;
|
use alloc::{
|
||||||
use core::{char, intrinsics::offset, str};
|
string::{String, ToString},
|
||||||
|
sync::{Arc, Weak},
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
use core::{
|
||||||
|
any::Any,
|
||||||
|
char,
|
||||||
|
intrinsics::offset,
|
||||||
|
str::{self, from_utf8},
|
||||||
|
};
|
||||||
|
|
||||||
const UART_SUCCESS: i32 = 0;
|
const UART_SUCCESS: i32 = 0;
|
||||||
const E_UART_BITS_RATE_ERROR: i32 = 1;
|
const E_UART_BITS_RATE_ERROR: i32 = 1;
|
||||||
@ -100,17 +116,34 @@ struct UartRegister {
|
|||||||
// @brief 串口设备结构体
|
// @brief 串口设备结构体
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Uart {
|
pub struct Uart {
|
||||||
state: DeviceState, // 设备状态
|
private_data: DevicePrivateData, // 设备状态
|
||||||
sys_info: Option<Arc<dyn IndexNode>>,
|
sys_info: Option<Arc<dyn IndexNode>>,
|
||||||
driver: Option<Arc<dyn PlatformDriver>>,
|
fs: Weak<DevFS>, // 文件系统
|
||||||
|
port: UartPort,
|
||||||
|
baud_rate: u32,
|
||||||
|
metadata: Metadata,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Uart {
|
impl Default for Uart {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
let mut metadata = Metadata::default();
|
||||||
|
metadata.file_type = FileType::CharDevice;
|
||||||
|
c_uart_init(UartPort::COM1.to_u16(), 115200);
|
||||||
Self {
|
Self {
|
||||||
state: DeviceState::NotInitialized,
|
private_data: DevicePrivateData::new(
|
||||||
|
IdTable::new(
|
||||||
|
"uart".to_string(),
|
||||||
|
DeviceNumber::new(DeviceNumber::from_major_minor(4, 64)),
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
CompatibleTable::new(vec!["uart"]),
|
||||||
|
DeviceState::NotInitialized,
|
||||||
|
),
|
||||||
sys_info: None,
|
sys_info: None,
|
||||||
driver: None,
|
fs: Weak::default(),
|
||||||
|
port: UartPort::COM1,
|
||||||
|
baud_rate: 115200,
|
||||||
|
metadata,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,12 +161,8 @@ impl Default for LockedUart {
|
|||||||
impl KObject for LockedUart {}
|
impl KObject for LockedUart {}
|
||||||
|
|
||||||
impl PlatformDevice for LockedUart {
|
impl PlatformDevice for LockedUart {
|
||||||
fn compatible_table(&self) -> platform::CompatibleTable {
|
|
||||||
platform::CompatibleTable::new(vec!["uart"])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_initialized(&self) -> bool {
|
fn is_initialized(&self) -> bool {
|
||||||
let state = self.0.lock().state;
|
let state = self.0.lock().private_data.state();
|
||||||
match state {
|
match state {
|
||||||
DeviceState::Initialized => true,
|
DeviceState::Initialized => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
@ -141,18 +170,20 @@ impl PlatformDevice for LockedUart {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_state(&self, set_state: DeviceState) {
|
fn set_state(&self, set_state: DeviceState) {
|
||||||
let state = &mut self.0.lock().state;
|
self.0.lock().private_data.set_state(set_state);
|
||||||
*state = set_state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_driver(&self, driver: Option<Arc<dyn PlatformDriver>>) {
|
fn compatible_table(&self) -> CompatibleTable {
|
||||||
self.0.lock().driver = driver;
|
return self.0.lock().private_data.compatible_table().clone();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device for LockedUart {
|
impl Device for LockedUart {
|
||||||
fn id_table(&self) -> IdTable {
|
fn id_table(&self) -> IdTable {
|
||||||
IdTable::new("uart", 0)
|
return IdTable::new(
|
||||||
|
"uart".to_string(),
|
||||||
|
DeviceNumber::new(DeviceNumber::from_major_minor(4, 64)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_sys_info(&self, sys_info: Option<Arc<dyn IndexNode>>) {
|
fn set_sys_info(&self, sys_info: Option<Arc<dyn IndexNode>>) {
|
||||||
@ -167,121 +198,222 @@ impl Device for LockedUart {
|
|||||||
DeviceType::Serial
|
DeviceType::Serial
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_any_ref(&'static self) -> &'static dyn core::any::Any {
|
fn as_any_ref(&self) -> &dyn Any {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @brief 串口驱动结构体
|
impl CharDevice for LockedUart {
|
||||||
#[repr(C)]
|
fn read(&self, len: usize, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||||
#[derive(Debug)]
|
let device = self.0.lock();
|
||||||
pub struct UartDriver {
|
if len > buf.len() {
|
||||||
port: UartPort,
|
return Err(SystemError::E2BIG);
|
||||||
baud_rate: u32,
|
|
||||||
sys_info: Option<Arc<dyn IndexNode>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for UartDriver {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
port: UartPort::COM1,
|
|
||||||
baud_rate: 115200,
|
|
||||||
sys_info: None,
|
|
||||||
}
|
}
|
||||||
|
kinfo!("------len: {:?}", len);
|
||||||
|
for i in 0..len {
|
||||||
|
buf[i] = Self::uart_read_byte(&device.port) as u8;
|
||||||
|
kinfo!("------buf[{:?}] = {:?}", i, buf[i]);
|
||||||
|
}
|
||||||
|
return Ok(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write(&self, len: usize, buf: &[u8]) -> Result<usize, SystemError> {
|
||||||
|
let device = self.0.lock();
|
||||||
|
if len > buf.len() {
|
||||||
|
return Err(SystemError::E2BIG);
|
||||||
|
}
|
||||||
|
Self::uart_send(
|
||||||
|
&device.port,
|
||||||
|
from_utf8(&buf[0..len]).map_err(|_| SystemError::EIO)?,
|
||||||
|
);
|
||||||
|
|
||||||
|
return Ok(len);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync(&self) -> Result<(), SystemError> {
|
||||||
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @brief 串口驱动结构体(加锁)
|
// impl TtyDevice for LockedUart {
|
||||||
#[derive(Debug)]
|
// fn ioctl(&self, cmd: String) -> Result<(), DeviceError> {
|
||||||
pub struct LockedUartDriver(SpinLock<UartDriver>);
|
// //TODO 补充详细信息
|
||||||
|
// Err(DeviceError::UnsupportedOperation)
|
||||||
|
// }
|
||||||
|
// fn state(&self) -> Result<TtyState, TtyError> {
|
||||||
|
// todo!()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
impl Default for LockedUartDriver {
|
impl IndexNode for LockedUart {
|
||||||
fn default() -> Self {
|
fn read_at(
|
||||||
Self(SpinLock::new(UartDriver::default()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KObject for LockedUartDriver {}
|
|
||||||
|
|
||||||
impl Driver for LockedUartDriver {
|
|
||||||
fn as_any_ref(&'static self) -> &'static dyn core::any::Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn id_table(&self) -> IdTable {
|
|
||||||
return IdTable::new("uart_driver", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_sys_info(&self, sys_info: Option<Arc<dyn IndexNode>>) {
|
|
||||||
self.0.lock().sys_info = sys_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sys_info(&self) -> Option<Arc<dyn IndexNode>> {
|
|
||||||
return self.0.lock().sys_info.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CharDevice for LockedUartDriver {
|
|
||||||
fn open(&self, _file: Arc<dyn IndexNode>) -> Result<(), crate::syscall::SystemError> {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn close(&self, _file: Arc<dyn IndexNode>) -> Result<(), crate::syscall::SystemError> {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LockedUartDriver {
|
|
||||||
/// @brief 创建串口驱动
|
|
||||||
/// @param port 端口号
|
|
||||||
/// baud_rate 波特率
|
|
||||||
/// sys_info: sys文件系统inode
|
|
||||||
/// @return
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn new(port: UartPort, baud_rate: u32, sys_info: Option<Arc<dyn IndexNode>>) -> Self {
|
|
||||||
Self(SpinLock::new(UartDriver::new(port, baud_rate, sys_info)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PlatformDriver for LockedUartDriver {
|
|
||||||
fn probe(
|
|
||||||
&self,
|
&self,
|
||||||
_device: Arc<dyn PlatformDevice>,
|
_offset: usize,
|
||||||
) -> Result<(), crate::driver::base::device::driver::DriverError> {
|
len: usize,
|
||||||
|
buf: &mut [u8],
|
||||||
|
_data: &mut FilePrivateData,
|
||||||
|
) -> Result<usize, SystemError> {
|
||||||
|
CharDevice::read(self, len, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_at(
|
||||||
|
&self,
|
||||||
|
_offset: usize,
|
||||||
|
len: usize,
|
||||||
|
buf: &[u8],
|
||||||
|
_data: &mut FilePrivateData,
|
||||||
|
) -> Result<usize, SystemError> {
|
||||||
|
CharDevice::write(self, len, buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn poll(&self) -> Result<PollStatus, SystemError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fs(&self) -> Arc<dyn FileSystem> {
|
||||||
|
return self
|
||||||
|
.0
|
||||||
|
.lock()
|
||||||
|
.fs
|
||||||
|
.clone()
|
||||||
|
.upgrade()
|
||||||
|
.expect("DevFS is not initialized inside Uart Device");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_ref(&self) -> &dyn Any {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list(&self) -> Result<Vec<String>, SystemError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn metadata(&self) -> Result<Metadata, SystemError> {
|
||||||
|
return Ok(self.0.lock().metadata.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open(
|
||||||
|
&self,
|
||||||
|
_data: &mut FilePrivateData,
|
||||||
|
_mode: &crate::filesystem::vfs::file::FileMode,
|
||||||
|
) -> Result<(), SystemError> {
|
||||||
|
// 若文件系统没有实现此方法,则返回“不支持”
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compatible_table(&self) -> platform::CompatibleTable {
|
fn close(&self, _data: &mut FilePrivateData) -> Result<(), SystemError> {
|
||||||
return CompatibleTable::new(vec!["uart"]);
|
// 若文件系统没有实现此方法,则返回“不支持”
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_metadata(&self, _metadata: &Metadata) -> Result<(), SystemError> {
|
||||||
|
// 若文件系统没有实现此方法,则返回“不支持”
|
||||||
|
return Ok(self.0.lock().metadata = _metadata.clone());
|
||||||
|
}
|
||||||
|
fn create(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
file_type: FileType,
|
||||||
|
mode: u32,
|
||||||
|
) -> Result<Arc<dyn IndexNode>, SystemError> {
|
||||||
|
// 若文件系统没有实现此方法,则默认调用其create_with_data方法。如果仍未实现,则会得到一个Err(-EOPNOTSUPP_OR_ENOTSUP)的返回值
|
||||||
|
return self.create_with_data(name, file_type, mode, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_with_data(
|
||||||
|
&self,
|
||||||
|
_name: &str,
|
||||||
|
_file_type: FileType,
|
||||||
|
_mode: u32,
|
||||||
|
_data: usize,
|
||||||
|
) -> Result<Arc<dyn IndexNode>, SystemError> {
|
||||||
|
// 若文件系统没有实现此方法,则返回“不支持”
|
||||||
|
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn link(&self, _name: &str, _other: &Arc<dyn IndexNode>) -> Result<(), SystemError> {
|
||||||
|
// 若文件系统没有实现此方法,则返回“不支持”
|
||||||
|
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unlink(&self, _name: &str) -> Result<(), SystemError> {
|
||||||
|
// 若文件系统没有实现此方法,则返回“不支持”
|
||||||
|
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rmdir(&self, _name: &str) -> Result<(), SystemError> {
|
||||||
|
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn move_(
|
||||||
|
&self,
|
||||||
|
_old_name: &str,
|
||||||
|
_target: &Arc<dyn IndexNode>,
|
||||||
|
_new_name: &str,
|
||||||
|
) -> Result<(), SystemError> {
|
||||||
|
// 若文件系统没有实现此方法,则返回“不支持”
|
||||||
|
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find(&self, _name: &str) -> Result<Arc<dyn IndexNode>, SystemError> {
|
||||||
|
// 若文件系统没有实现此方法,则返回“不支持”
|
||||||
|
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_entry_name(&self, _ino: crate::filesystem::vfs::InodeId) -> Result<String, SystemError> {
|
||||||
|
// 若文件系统没有实现此方法,则返回“不支持”
|
||||||
|
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_entry_name_and_metadata(
|
||||||
|
&self,
|
||||||
|
ino: crate::filesystem::vfs::InodeId,
|
||||||
|
) -> Result<(String, Metadata), SystemError> {
|
||||||
|
// 如果有条件,请在文件系统中使用高效的方式实现本接口,而不是依赖这个低效率的默认实现。
|
||||||
|
let name = self.get_entry_name(ino)?;
|
||||||
|
let entry = self.find(&name)?;
|
||||||
|
return Ok((name, entry.metadata()?));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ioctl(&self, _cmd: u32, _data: usize) -> Result<usize, SystemError> {
|
||||||
|
// 若文件系统没有实现此方法,则返回“不支持”
|
||||||
|
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mount(
|
||||||
|
&self,
|
||||||
|
_fs: Arc<dyn FileSystem>,
|
||||||
|
) -> Result<Arc<crate::filesystem::vfs::MountFS>, SystemError> {
|
||||||
|
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn truncate(&self, _len: usize) -> Result<(), SystemError> {
|
||||||
|
return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync(&self) -> Result<(), SystemError> {
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UartDriver {
|
impl DeviceINode for LockedUart {
|
||||||
/// @brief 创建串口驱动
|
fn set_fs(&self, fs: Weak<DevFS>) {
|
||||||
/// @param port 端口号
|
self.0.lock().fs = fs;
|
||||||
/// baud_rate 波特率
|
|
||||||
/// sys_info: sys文件系统inode
|
|
||||||
/// @return 返回串口驱动
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn new(port: UartPort, baud_rate: u32, sys_info: Option<Arc<dyn IndexNode>>) -> Self {
|
|
||||||
Self {
|
|
||||||
port,
|
|
||||||
baud_rate,
|
|
||||||
sys_info,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LockedUart {
|
||||||
/// @brief 串口初始化
|
/// @brief 串口初始化
|
||||||
/// @param uart_port 端口号
|
/// @param uart_port 端口号
|
||||||
/// @param baud_rate 波特率
|
/// @param baud_rate 波特率
|
||||||
/// @return 初始化成功,返回0,失败,返回错误信息
|
/// @return 初始化成功,返回0,失败,返回错误信息
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn uart_init(uart_port: &UartPort, baud_rate: u32) -> Result<i32, &'static str> {
|
pub fn uart_init(uart_port: &UartPort, baud_rate: u32) -> Result<(), DeviceError> {
|
||||||
let message: &'static str = "uart init.";
|
let message: &'static str = "uart init.";
|
||||||
let port = uart_port.to_u16();
|
let port = uart_port.to_u16();
|
||||||
// 错误的比特率
|
// 错误的比特率
|
||||||
if baud_rate > UART_MAX_BITS_RATE || UART_MAX_BITS_RATE % baud_rate != 0 {
|
if baud_rate > UART_MAX_BITS_RATE || UART_MAX_BITS_RATE % baud_rate != 0 {
|
||||||
return Err("uart init error.");
|
return Err(DeviceError::InitializeFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -300,15 +432,15 @@ impl UartDriver {
|
|||||||
|
|
||||||
// Check if serial is faulty (i.e: not same byte as sent)
|
// Check if serial is faulty (i.e: not same byte as sent)
|
||||||
if io_in8(port + 0) != 0xAE {
|
if io_in8(port + 0) != 0xAE {
|
||||||
return Err("uart faulty");
|
return Err(DeviceError::InitializeFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If serial is not faulty set it in normal operation mode
|
// If serial is not faulty set it in normal operation mode
|
||||||
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
|
// (not-loopback with IRQs enabled and OUT#1 and OUT#2 bits enabled)
|
||||||
io_out8(port + 4, 0x08);
|
io_out8(port + 4, 0x08);
|
||||||
}
|
}
|
||||||
UartDriver::uart_send(uart_port, message);
|
Self::uart_send(uart_port, message);
|
||||||
Ok(0)
|
Ok(())
|
||||||
/*
|
/*
|
||||||
Notice that the initialization code above writes to [PORT + 1]
|
Notice that the initialization code above writes to [PORT + 1]
|
||||||
twice with different values. This is once to write to the Divisor
|
twice with different values. This is once to write to the Divisor
|
||||||
@ -342,13 +474,12 @@ impl UartDriver {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn uart_send(uart_port: &UartPort, s: &str) {
|
fn uart_send(uart_port: &UartPort, s: &str) {
|
||||||
let port = uart_port.to_u16();
|
let port = uart_port.to_u16();
|
||||||
while UartDriver::is_transmit_empty(port) == false {
|
while Self::is_transmit_empty(port) == false {} //TODO:pause
|
||||||
for c in s.bytes() {
|
for c in s.bytes() {
|
||||||
unsafe {
|
unsafe {
|
||||||
io_out8(port, c);
|
io_out8(port, c);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} //TODO:pause
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief 串口接收一个字节
|
/// @brief 串口接收一个字节
|
||||||
@ -357,8 +488,8 @@ impl UartDriver {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn uart_read_byte(uart_port: &UartPort) -> char {
|
fn uart_read_byte(uart_port: &UartPort) -> char {
|
||||||
let port = uart_port.to_u16();
|
let port = uart_port.to_u16();
|
||||||
while UartDriver::serial_received(port) == false {} //TODO:pause
|
while Self::serial_received(port) == false {} //TODO:pause
|
||||||
unsafe { io_in8(port) as char }
|
return unsafe { io_in8(port) as char };
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -367,12 +498,112 @@ impl UartDriver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @brief 串口驱动结构体
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UartDriver {
|
||||||
|
id_table: IdTable,
|
||||||
|
|
||||||
|
sys_info: Option<Arc<dyn IndexNode>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for UartDriver {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
id_table: IdTable::new(
|
||||||
|
"ttyS".to_string(),
|
||||||
|
DeviceNumber::new(DeviceNumber::from_major_minor(4, 64)),
|
||||||
|
),
|
||||||
|
|
||||||
|
sys_info: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @brief 串口驱动结构体(加锁)
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct LockedUartDriver(SpinLock<UartDriver>);
|
||||||
|
|
||||||
|
impl Default for LockedUartDriver {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(SpinLock::new(UartDriver::default()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KObject for LockedUartDriver {}
|
||||||
|
|
||||||
|
impl Driver for LockedUartDriver {
|
||||||
|
fn as_any_ref(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn id_table(&self) -> IdTable {
|
||||||
|
return IdTable::new("uart_driver".to_string(), DeviceNumber::new(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_sys_info(&self, sys_info: Option<Arc<dyn IndexNode>>) {
|
||||||
|
self.0.lock().sys_info = sys_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sys_info(&self) -> Option<Arc<dyn IndexNode>> {
|
||||||
|
return self.0.lock().sys_info.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn probe(&self, data: &DevicePrivateData) -> Result<(), DriverError> {
|
||||||
|
let table = data.compatible_table();
|
||||||
|
if table.matches(&CompatibleTable::new(vec!["uart"])) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
return Err(DriverError::ProbeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load(
|
||||||
|
&self,
|
||||||
|
_data: DevicePrivateData,
|
||||||
|
_resource: Option<DeviceResource>,
|
||||||
|
) -> Result<Arc<dyn Device>, DriverError> {
|
||||||
|
return Err(DriverError::UnsupportedOperation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LockedUartDriver {
|
||||||
|
/// @brief 创建串口驱动
|
||||||
|
/// @param sys_info: sys文件系统inode
|
||||||
|
/// @return
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new(sys_info: Option<Arc<dyn IndexNode>>) -> Self {
|
||||||
|
Self(SpinLock::new(UartDriver::new(sys_info)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlatformDriver for LockedUartDriver {
|
||||||
|
fn compatible_table(&self) -> CompatibleTable {
|
||||||
|
return CompatibleTable::new(vec!["uart"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UartDriver {
|
||||||
|
/// @brief 创建串口驱动
|
||||||
|
/// @param sys_info: sys文件系统inode
|
||||||
|
/// @return 返回串口驱动
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new(sys_info: Option<Arc<dyn IndexNode>>) -> Self {
|
||||||
|
Self {
|
||||||
|
id_table: IdTable::new(
|
||||||
|
"ttyS".to_string(),
|
||||||
|
DeviceNumber::new(DeviceNumber::from_major_minor(4, 64)),
|
||||||
|
),
|
||||||
|
sys_info,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///@brief 发送数据
|
///@brief 发送数据
|
||||||
///@param port 端口号
|
///@param port 端口号
|
||||||
///@param c 要发送的数据
|
///@param c 要发送的数据
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn c_uart_send(port: u16, c: u8) {
|
pub extern "C" fn c_uart_send(port: u16, c: u8) {
|
||||||
while UartDriver::is_transmit_empty(port) == false {} //TODO:pause
|
while LockedUart::is_transmit_empty(port) == false {} //TODO:pause
|
||||||
unsafe {
|
unsafe {
|
||||||
io_out8(port, c);
|
io_out8(port, c);
|
||||||
}
|
}
|
||||||
@ -383,7 +614,7 @@ pub extern "C" fn c_uart_send(port: u16, c: u8) {
|
|||||||
///@return u8 接收到的数据
|
///@return u8 接收到的数据
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn c_uart_read(port: u16) -> u8 {
|
pub extern "C" fn c_uart_read(port: u16) -> u8 {
|
||||||
while UartDriver::serial_received(port) == false {} //TODO:pause
|
while LockedUart::serial_received(port) == false {} //TODO:pause
|
||||||
unsafe { io_in8(port) }
|
unsafe { io_in8(port) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,13 +686,18 @@ pub extern "C" fn c_uart_init(port: u16, baud_rate: u32) -> i32 {
|
|||||||
/// @param none
|
/// @param none
|
||||||
/// @return 初始化成功,返回(),失败,返回错误码
|
/// @return 初始化成功,返回(),失败,返回错误码
|
||||||
pub fn uart_init() -> Result<(), SystemError> {
|
pub fn uart_init() -> Result<(), SystemError> {
|
||||||
let device_inode = bus_device_register("platform:0", &UART_DEV.id_table().to_name())
|
// 以后设备管理初始化完善后不应该出现这种代码,应该在 Driver load 一个设备,即返回设备实例之前就完成设备的 init ,不应该用 lazy_init 在设备上
|
||||||
|
let dev = UART_DEV.0.lock();
|
||||||
|
LockedUart::uart_init(&dev.port, dev.baud_rate).map_err(|_| SystemError::ENODEV)?;
|
||||||
|
drop(dev);
|
||||||
|
let device_inode = bus_device_register("platform:0", &UART_DEV.id_table().name())
|
||||||
.expect("uart device register error");
|
.expect("uart device register error");
|
||||||
UART_DEV.set_sys_info(Some(device_inode));
|
UART_DEV.set_sys_info(Some(device_inode));
|
||||||
let driver_inode = bus_driver_register("platform:0", &UART_DRV.id_table().to_name())
|
let driver_inode = bus_driver_register("platform:0", &UART_DRV.id_table().name())
|
||||||
.expect("uart driver register error");
|
.expect("uart driver register error");
|
||||||
UART_DRV.set_sys_info(Some(driver_inode));
|
UART_DRV.set_sys_info(Some(driver_inode));
|
||||||
UART_DEV.set_driver(Some(UART_DRV.clone()));
|
|
||||||
UART_DEV.set_state(DeviceState::Initialized);
|
UART_DEV.set_state(DeviceState::Initialized);
|
||||||
|
devfs_register(&UART_DEV.id_table().name(), UART_DEV.clone())?;
|
||||||
|
DEVICE_MANAGER.add_device(UART_DEV.id_table().clone(), UART_DEV.clone());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
81
kernel/src/driver/uart/uart_driver.rs
Normal file
81
kernel/src/driver/uart/uart_driver.rs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
|
use crate::driver::base::device::{Device, DeviceResource, DEVICE_MANAGER};
|
||||||
|
use crate::driver::base::map::CharDevOps;
|
||||||
|
use crate::driver::base::platform::CompatibleTable;
|
||||||
|
use crate::{
|
||||||
|
driver::{
|
||||||
|
base::device::{driver::DriverError, DevicePrivateData, IdTable},
|
||||||
|
Driver,
|
||||||
|
},
|
||||||
|
libs::spinlock::SpinLock,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::uart_device::LockedUart;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref UART_COMPAT_TABLE: CompatibleTable = CompatibleTable::new(vec!["uart"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InnerUartDriver {
|
||||||
|
id_table: IdTable,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct UartDriver(SpinLock<InnerUartDriver>);
|
||||||
|
|
||||||
|
impl Default for UartDriver {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self(SpinLock::new(InnerUartDriver {
|
||||||
|
id_table: IdTable::default(),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Driver for UartDriver {
|
||||||
|
fn probe(&self, data: &DevicePrivateData) -> Result<(), DriverError> {
|
||||||
|
let compatible_table = data.compatible_table();
|
||||||
|
if compatible_table.matches(&UART_COMPAT_TABLE) {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(DriverError::ProbeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load(
|
||||||
|
&self,
|
||||||
|
data: DevicePrivateData,
|
||||||
|
_resource: Option<DeviceResource>,
|
||||||
|
) -> Result<Arc<dyn Device>, DriverError> {
|
||||||
|
if let Some(device) = DEVICE_MANAGER.get_device(data.id_table()) {
|
||||||
|
return Ok(device.clone());
|
||||||
|
}
|
||||||
|
let compatible_table = data.compatible_table();
|
||||||
|
if compatible_table.matches(&UART_COMPAT_TABLE) {
|
||||||
|
let device = LockedUart::default();
|
||||||
|
let arc_device = Arc::new(device);
|
||||||
|
DEVICE_MANAGER.add_device(data.id_table().clone(), arc_device.clone());
|
||||||
|
CharDevOps::cdev_add(arc_device.clone(), data.id_table().clone(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(DriverError::ProbeError);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn id_table(&self) -> IdTable {
|
||||||
|
let driver = self.0.lock();
|
||||||
|
return driver.id_table.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_ref(&'static self) -> &'static dyn core::any::Any {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_sys_info(&self, _sys_info: Option<Arc<dyn crate::filesystem::vfs::IndexNode>>) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sys_info(&self) -> Option<Arc<dyn crate::filesystem::vfs::IndexNode>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
@ -8,8 +8,11 @@ use super::vfs::{
|
|||||||
FileSystem, FileType, FsInfo, IndexNode, Metadata, PollStatus,
|
FileSystem, FileType, FsInfo, IndexNode, Metadata, PollStatus,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
kerror,
|
kerror, kinfo,
|
||||||
libs::spinlock::{SpinLock, SpinLockGuard},
|
libs::{
|
||||||
|
once::Once,
|
||||||
|
spinlock::{SpinLock, SpinLockGuard},
|
||||||
|
},
|
||||||
syscall::SystemError,
|
syscall::SystemError,
|
||||||
time::TimeSpec,
|
time::TimeSpec,
|
||||||
};
|
};
|
||||||
@ -529,3 +532,23 @@ pub fn devfs_register<T: DeviceINode>(name: &str, device: Arc<T>) -> Result<(),
|
|||||||
pub fn devfs_unregister<T: DeviceINode>(name: &str, device: Arc<T>) -> Result<(), SystemError> {
|
pub fn devfs_unregister<T: DeviceINode>(name: &str, device: Arc<T>) -> Result<(), SystemError> {
|
||||||
return devfs_exact_ref!().unregister_device(name, device);
|
return devfs_exact_ref!().unregister_device(name, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn devfs_init() -> Result<(), SystemError> {
|
||||||
|
static INIT: Once = Once::new();
|
||||||
|
let mut result = None;
|
||||||
|
INIT.call_once(|| {
|
||||||
|
kinfo!("Initializing ProcFS...");
|
||||||
|
// 创建 devfs 实例
|
||||||
|
let devfs: Arc<DevFS> = DevFS::new();
|
||||||
|
// devfs 挂载
|
||||||
|
let _t = ROOT_INODE()
|
||||||
|
.find("dev")
|
||||||
|
.expect("Cannot find /dev")
|
||||||
|
.mount(devfs)
|
||||||
|
.expect("Failed to mount devfs");
|
||||||
|
kinfo!("DevFS mounted.");
|
||||||
|
result = Some(Ok(()));
|
||||||
|
});
|
||||||
|
|
||||||
|
return result.unwrap();
|
||||||
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
use alloc::{sync::Arc, vec::Vec};
|
use alloc::{sync::Arc, vec::Vec};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
filesystem::vfs::io::{device::LBA_SIZE, disk_info::Partition, SeekFrom},
|
driver::base::block::{block_device::LBA_SIZE, disk_info::Partition, SeekFrom},
|
||||||
kerror,
|
kerror,
|
||||||
libs::vec_cursor::VecCursor,
|
libs::vec_cursor::VecCursor,
|
||||||
syscall::SystemError,
|
syscall::SystemError,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
use core::{cmp::min, intrinsics::unlikely};
|
use core::{cmp::min, intrinsics::unlikely};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
filesystem::vfs::io::{device::LBA_SIZE, SeekFrom},
|
driver::base::block::{block_device::LBA_SIZE, SeekFrom},
|
||||||
kwarn,
|
kwarn,
|
||||||
libs::vec_cursor::VecCursor,
|
libs::vec_cursor::VecCursor,
|
||||||
syscall::SystemError,
|
syscall::SystemError,
|
||||||
@ -130,7 +130,7 @@ impl FATFile {
|
|||||||
|
|
||||||
// 从磁盘上读取数据
|
// 从磁盘上读取数据
|
||||||
let offset = fs.cluster_bytes_offset(current_cluster) + in_cluster_offset;
|
let offset = fs.cluster_bytes_offset(current_cluster) + in_cluster_offset;
|
||||||
let r = fs.partition.disk().device().read_at(
|
let r = fs.partition.disk().read_at_bytes(
|
||||||
offset as usize,
|
offset as usize,
|
||||||
end_len,
|
end_len,
|
||||||
&mut buf[start..start + end_len],
|
&mut buf[start..start + end_len],
|
||||||
@ -198,7 +198,7 @@ impl FATFile {
|
|||||||
// 计算本次写入位置在磁盘上的偏移量
|
// 计算本次写入位置在磁盘上的偏移量
|
||||||
let offset = fs.cluster_bytes_offset(current_cluster) + in_cluster_bytes_offset;
|
let offset = fs.cluster_bytes_offset(current_cluster) + in_cluster_bytes_offset;
|
||||||
// 写入磁盘
|
// 写入磁盘
|
||||||
let w: usize = fs.partition.disk().device().write_at(
|
let w: usize = fs.partition.disk().write_at(
|
||||||
offset as usize,
|
offset as usize,
|
||||||
end_len,
|
end_len,
|
||||||
&buf[start..start + end_len],
|
&buf[start..start + end_len],
|
||||||
@ -326,11 +326,9 @@ impl FATFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let zeroes: Vec<u8> = vec![0u8; (range_end - range_start) as usize];
|
let zeroes: Vec<u8> = vec![0u8; (range_end - range_start) as usize];
|
||||||
fs.partition.disk().device().write_at(
|
fs.partition
|
||||||
range_start as usize,
|
.disk()
|
||||||
zeroes.len(),
|
.write_at(range_start as usize, zeroes.len(), zeroes.as_slice())?;
|
||||||
zeroes.as_slice(),
|
|
||||||
)?;
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,11 +610,10 @@ impl FATDir {
|
|||||||
LongDirEntry::validate_long_name(name)?;
|
LongDirEntry::validate_long_name(name)?;
|
||||||
// 目标目录项
|
// 目标目录项
|
||||||
let mut short_entry = ShortDirEntry::default();
|
let mut short_entry = ShortDirEntry::default();
|
||||||
// kdebug!("to allocate cluster");
|
|
||||||
let first_cluster: Cluster = fs.allocate_cluster(None)?;
|
let first_cluster: Cluster = fs.allocate_cluster(None)?;
|
||||||
short_entry.set_first_cluster(first_cluster);
|
short_entry.set_first_cluster(first_cluster);
|
||||||
|
|
||||||
// kdebug!("to create dot");
|
|
||||||
// === 接下来在子目录中创建'.'目录项和'..'目录项
|
// === 接下来在子目录中创建'.'目录项和'..'目录项
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
// '.'目录项
|
// '.'目录项
|
||||||
@ -632,7 +629,6 @@ impl FATDir {
|
|||||||
// 偏移量加上一个目录项的长度
|
// 偏移量加上一个目录项的长度
|
||||||
offset += FATRawDirEntry::DIR_ENTRY_LEN;
|
offset += FATRawDirEntry::DIR_ENTRY_LEN;
|
||||||
|
|
||||||
// kdebug!("to create dot dot");
|
|
||||||
// '..'目录项
|
// '..'目录项
|
||||||
let mut dot_dot_entry = ShortDirEntry::default();
|
let mut dot_dot_entry = ShortDirEntry::default();
|
||||||
dot_dot_entry.name = ShortNameGenerator::new("..").generate().unwrap();
|
dot_dot_entry.name = ShortNameGenerator::new("..").generate().unwrap();
|
||||||
|
@ -9,7 +9,7 @@ use alloc::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
filesystem::vfs::io::{device::LBA_SIZE, disk_info::Partition, SeekFrom},
|
driver::base::block::{block_device::LBA_SIZE, disk_info::Partition, SeekFrom},
|
||||||
filesystem::vfs::{
|
filesystem::vfs::{
|
||||||
core::generate_inode_id,
|
core::generate_inode_id,
|
||||||
file::{FileMode, FilePrivateData},
|
file::{FileMode, FilePrivateData},
|
||||||
@ -1174,8 +1174,7 @@ impl FATFileSystem {
|
|||||||
let offset: usize = self.cluster_bytes_offset(cluster) as usize;
|
let offset: usize = self.cluster_bytes_offset(cluster) as usize;
|
||||||
self.partition
|
self.partition
|
||||||
.disk()
|
.disk()
|
||||||
.device()
|
.write_at_bytes(offset, zeros.len(), zeros.as_slice())?;
|
||||||
.write_at(offset, zeros.len(), zeros.as_slice())?;
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1425,7 +1424,6 @@ impl IndexNode for LockedFATInode {
|
|||||||
_mode: u32,
|
_mode: u32,
|
||||||
) -> Result<Arc<dyn IndexNode>, SystemError> {
|
) -> Result<Arc<dyn IndexNode>, SystemError> {
|
||||||
// 由于FAT32不支持文件权限的功能,因此忽略mode参数
|
// 由于FAT32不支持文件权限的功能,因此忽略mode参数
|
||||||
|
|
||||||
let mut guard: SpinLockGuard<FATInode> = self.0.lock();
|
let mut guard: SpinLockGuard<FATInode> = self.0.lock();
|
||||||
let fs: &Arc<FATFileSystem> = &guard.fs.upgrade().unwrap();
|
let fs: &Arc<FATFileSystem> = &guard.fs.upgrade().unwrap();
|
||||||
|
|
||||||
|
@ -16,8 +16,11 @@ use crate::{
|
|||||||
FileType,
|
FileType,
|
||||||
},
|
},
|
||||||
include::bindings::bindings::{pid_t, process_find_pcb_by_pid},
|
include::bindings::bindings::{pid_t, process_find_pcb_by_pid},
|
||||||
kerror,
|
kerror, kinfo,
|
||||||
libs::spinlock::{SpinLock, SpinLockGuard},
|
libs::{
|
||||||
|
once::Once,
|
||||||
|
spinlock::{SpinLock, SpinLockGuard},
|
||||||
|
},
|
||||||
syscall::SystemError,
|
syscall::SystemError,
|
||||||
time::TimeSpec,
|
time::TimeSpec,
|
||||||
};
|
};
|
||||||
@ -704,3 +707,24 @@ pub fn procfs_unregister_pid(pid: pid_t) -> Result<(), SystemError> {
|
|||||||
// 调用解除注册函数
|
// 调用解除注册函数
|
||||||
return procfs.unregister_pid(pid);
|
return procfs.unregister_pid(pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn procfs_init() -> Result<(), SystemError> {
|
||||||
|
static INIT: Once = Once::new();
|
||||||
|
let mut result = None;
|
||||||
|
INIT.call_once(|| {
|
||||||
|
kinfo!("Initializing ProcFS...");
|
||||||
|
// 创建 sysfs 实例
|
||||||
|
let procfs: Arc<ProcFS> = ProcFS::new();
|
||||||
|
|
||||||
|
// sysfs 挂载
|
||||||
|
let _t = ROOT_INODE()
|
||||||
|
.find("proc")
|
||||||
|
.expect("Cannot find /proc")
|
||||||
|
.mount(procfs)
|
||||||
|
.expect("Failed to mount proc");
|
||||||
|
kinfo!("ProcFS mounted.");
|
||||||
|
result = Some(Ok(()));
|
||||||
|
});
|
||||||
|
|
||||||
|
return result.unwrap();
|
||||||
|
}
|
||||||
|
@ -3,7 +3,13 @@ use super::vfs::{
|
|||||||
PollStatus,
|
PollStatus,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
libs::spinlock::{SpinLock, SpinLockGuard},
|
driver::base::platform::platform_bus_init,
|
||||||
|
filesystem::{sysfs::bus::sys_bus_init, vfs::ROOT_INODE},
|
||||||
|
kdebug, kinfo,
|
||||||
|
libs::{
|
||||||
|
once::Once,
|
||||||
|
spinlock::{SpinLock, SpinLockGuard},
|
||||||
|
},
|
||||||
syscall::SystemError,
|
syscall::SystemError,
|
||||||
time::TimeSpec,
|
time::TimeSpec,
|
||||||
};
|
};
|
||||||
@ -136,10 +142,7 @@ impl SysFS {
|
|||||||
},
|
},
|
||||||
Err(_) => panic!("SysFS: Failed to create /sys/fs"),
|
Err(_) => panic!("SysFS: Failed to create /sys/fs"),
|
||||||
}
|
}
|
||||||
// 初始化platform总线
|
|
||||||
crate::driver::base::platform::platform_bus_init().expect("platform bus init failed");
|
|
||||||
// 初始化串口
|
|
||||||
crate::driver::uart::uart::uart_init().expect("initilize uart error");
|
|
||||||
return sysfs;
|
return sysfs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -446,3 +449,33 @@ impl SysFSInode {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn sysfs_init() -> Result<(), SystemError> {
|
||||||
|
static INIT: Once = Once::new();
|
||||||
|
let mut result = None;
|
||||||
|
INIT.call_once(|| {
|
||||||
|
kinfo!("Initializing SysFS...");
|
||||||
|
// 创建 sysfs 实例
|
||||||
|
let sysfs: Arc<SysFS> = SysFS::new();
|
||||||
|
|
||||||
|
// sysfs 挂载
|
||||||
|
let _t = ROOT_INODE()
|
||||||
|
.find("sys")
|
||||||
|
.expect("Cannot find /sys")
|
||||||
|
.mount(sysfs)
|
||||||
|
.expect("Failed to mount sysfs");
|
||||||
|
kinfo!("SysFS mounted.");
|
||||||
|
|
||||||
|
// 初始化platform总线
|
||||||
|
platform_bus_init().expect("platform bus init failed");
|
||||||
|
|
||||||
|
sys_bus_init(&SYS_BUS_INODE()).unwrap_or_else(|err| {
|
||||||
|
panic!("sys_bus_init failed: {:?}", err);
|
||||||
|
});
|
||||||
|
|
||||||
|
kdebug!("sys_bus_init result: {:?}", SYS_BUS_INODE().list());
|
||||||
|
result = Some(Ok(()));
|
||||||
|
});
|
||||||
|
|
||||||
|
return result.unwrap();
|
||||||
|
}
|
||||||
|
@ -7,17 +7,20 @@ use core::{
|
|||||||
use alloc::{boxed::Box, format, string::ToString, sync::Arc};
|
use alloc::{boxed::Box, format, string::ToString, sync::Arc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
driver::disk::ahci::{self},
|
driver::{
|
||||||
|
base::block::disk_info::Partition,
|
||||||
|
disk::ahci::{self},
|
||||||
|
},
|
||||||
filesystem::{
|
filesystem::{
|
||||||
devfs::DevFS,
|
devfs::devfs_init,
|
||||||
fat::fs::FATFileSystem,
|
fat::fs::FATFileSystem,
|
||||||
procfs::ProcFS,
|
procfs::procfs_init,
|
||||||
ramfs::RamFS,
|
ramfs::RamFS,
|
||||||
sysfs::SysFS,
|
sysfs::sysfs_init,
|
||||||
vfs::{mount::MountFS, FileSystem, FileType},
|
vfs::{mount::MountFS, FileSystem, FileType},
|
||||||
},
|
},
|
||||||
include::bindings::bindings::PAGE_4K_SIZE,
|
include::bindings::bindings::PAGE_4K_SIZE,
|
||||||
kerror, kinfo,
|
kdebug, kerror, kinfo,
|
||||||
syscall::SystemError,
|
syscall::SystemError,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -65,37 +68,13 @@ pub extern "C" fn vfs_init() -> i32 {
|
|||||||
root_inode
|
root_inode
|
||||||
.create("sys", FileType::Dir, 0o777)
|
.create("sys", FileType::Dir, 0o777)
|
||||||
.expect("Failed to create /sys");
|
.expect("Failed to create /sys");
|
||||||
|
kdebug!("dir in root:{:?}", root_inode.list());
|
||||||
|
|
||||||
// // 创建procfs实例
|
procfs_init().expect("Failed to initialize procfs");
|
||||||
let procfs: Arc<ProcFS> = ProcFS::new();
|
|
||||||
|
|
||||||
// procfs挂载
|
devfs_init().expect("Failed to initialize devfs");
|
||||||
let _t = root_inode
|
|
||||||
.find("proc")
|
|
||||||
.expect("Cannot find /proc")
|
|
||||||
.mount(procfs)
|
|
||||||
.expect("Failed to mount procfs.");
|
|
||||||
kinfo!("ProcFS mounted.");
|
|
||||||
|
|
||||||
// 创建 devfs 实例
|
sysfs_init().expect("Failed to initialize sysfs");
|
||||||
let devfs: Arc<DevFS> = DevFS::new();
|
|
||||||
// devfs 挂载
|
|
||||||
let _t = root_inode
|
|
||||||
.find("dev")
|
|
||||||
.expect("Cannot find /dev")
|
|
||||||
.mount(devfs)
|
|
||||||
.expect("Failed to mount devfs");
|
|
||||||
kinfo!("DevFS mounted.");
|
|
||||||
|
|
||||||
// 创建 sysfs 实例
|
|
||||||
let sysfs: Arc<SysFS> = SysFS::new();
|
|
||||||
// sysfs 挂载
|
|
||||||
let _t = root_inode
|
|
||||||
.find("sys")
|
|
||||||
.expect("Cannot find /sys")
|
|
||||||
.mount(sysfs)
|
|
||||||
.expect("Failed to mount sysfs");
|
|
||||||
kinfo!("SysFS mounted.");
|
|
||||||
|
|
||||||
let root_inode = ROOT_INODE().list().expect("VFS init failed");
|
let root_inode = ROOT_INODE().list().expect("VFS init failed");
|
||||||
if root_inode.len() > 0 {
|
if root_inode.len() > 0 {
|
||||||
@ -117,14 +96,14 @@ fn do_migrate(
|
|||||||
let mountpoint = if r.is_err() {
|
let mountpoint = if r.is_err() {
|
||||||
new_root_inode
|
new_root_inode
|
||||||
.create(mountpoint_name, FileType::Dir, 0o777)
|
.create(mountpoint_name, FileType::Dir, 0o777)
|
||||||
.expect(format!("Failed to create '/{mountpoint_name}'").as_str())
|
.expect(format!("Failed to create '/{mountpoint_name}' in migrating").as_str())
|
||||||
} else {
|
} else {
|
||||||
r.unwrap()
|
r.unwrap()
|
||||||
};
|
};
|
||||||
// 迁移挂载点
|
// 迁移挂载点
|
||||||
mountpoint
|
mountpoint
|
||||||
.mount(fs.inner_filesystem())
|
.mount(fs.inner_filesystem())
|
||||||
.expect(format!("Failed to migrate {mountpoint_name}").as_str());
|
.expect(format!("Failed to migrate {mountpoint_name} ").as_str());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,13 +147,12 @@ fn migrate_virtual_filesystem(new_fs: Arc<dyn FileSystem>) -> Result<(), SystemE
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn mount_root_fs() -> i32 {
|
pub extern "C" fn mount_root_fs() -> i32 {
|
||||||
kinfo!("Try to mount FAT32 as root fs...");
|
kinfo!("Try to mount FAT32 as root fs...");
|
||||||
let partiton: Arc<crate::filesystem::vfs::io::disk_info::Partition> =
|
let partiton: Arc<Partition> = ahci::get_disks_by_name("ahci_disk_0".to_string())
|
||||||
ahci::get_disks_by_name("ahci_disk_0".to_string())
|
.unwrap()
|
||||||
.unwrap()
|
.0
|
||||||
.0
|
.lock()
|
||||||
.lock()
|
.partitions[0]
|
||||||
.partitions[0]
|
.clone();
|
||||||
.clone();
|
|
||||||
|
|
||||||
let fatfs: Result<Arc<FATFileSystem>, SystemError> = FATFileSystem::new(partiton);
|
let fatfs: Result<Arc<FATFileSystem>, SystemError> = FATFileSystem::new(partiton);
|
||||||
if fatfs.is_err() {
|
if fatfs.is_err() {
|
||||||
|
@ -3,9 +3,15 @@ use core::mem::MaybeUninit;
|
|||||||
use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
|
use alloc::{boxed::Box, string::String, sync::Arc, vec::Vec};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::asm::current::current_pcb, driver::tty::TtyFilePrivateData,
|
arch::asm::current::current_pcb,
|
||||||
filesystem::procfs::ProcfsFilePrivateData, filesystem::vfs::io::SeekFrom,
|
driver::{
|
||||||
include::bindings::bindings::process_control_block, kerror, syscall::SystemError,
|
base::{block::SeekFrom, device::DevicePrivateData},
|
||||||
|
tty::TtyFilePrivateData,
|
||||||
|
},
|
||||||
|
filesystem::procfs::ProcfsFilePrivateData,
|
||||||
|
include::bindings::bindings::process_control_block,
|
||||||
|
kerror,
|
||||||
|
syscall::SystemError,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Dirent, FileType, IndexNode, Metadata};
|
use super::{Dirent, FileType, IndexNode, Metadata};
|
||||||
@ -15,7 +21,9 @@ use super::{Dirent, FileType, IndexNode, Metadata};
|
|||||||
pub enum FilePrivateData {
|
pub enum FilePrivateData {
|
||||||
/// procfs文件私有信息
|
/// procfs文件私有信息
|
||||||
Procfs(ProcfsFilePrivateData),
|
Procfs(ProcfsFilePrivateData),
|
||||||
/// Tty设备的私有信息
|
/// 设备文件的私有信息
|
||||||
|
DevFS(DevicePrivateData),
|
||||||
|
/// tty设备文件的私有信息
|
||||||
Tty(TtyFilePrivateData),
|
Tty(TtyFilePrivateData),
|
||||||
/// 不需要文件私有信息
|
/// 不需要文件私有信息
|
||||||
Unused,
|
Unused,
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
pub mod core;
|
pub mod core;
|
||||||
pub mod fcntl;
|
pub mod fcntl;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
pub mod io;
|
|
||||||
pub mod mount;
|
pub mod mount;
|
||||||
pub mod syscall;
|
pub mod syscall;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
@ -2,8 +2,8 @@ use alloc::{boxed::Box, sync::Arc, vec::Vec};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::asm::current::current_pcb,
|
arch::asm::current::current_pcb,
|
||||||
|
driver::base::block::SeekFrom,
|
||||||
filesystem::vfs::file::FileDescriptorVec,
|
filesystem::vfs::file::FileDescriptorVec,
|
||||||
filesystem::vfs::io::SeekFrom,
|
|
||||||
include::bindings::bindings::{verify_area, AT_REMOVEDIR, PAGE_4K_SIZE, PROC_MAX_FD_NUM},
|
include::bindings::bindings::{verify_area, AT_REMOVEDIR, PAGE_4K_SIZE, PROC_MAX_FD_NUM},
|
||||||
kerror,
|
kerror,
|
||||||
syscall::{Syscall, SystemError},
|
syscall::{Syscall, SystemError},
|
||||||
|
@ -10,7 +10,7 @@ use elf::{endian::AnyEndian, file::FileHeader, segment::ProgramHeader};
|
|||||||
use crate::{
|
use crate::{
|
||||||
arch::MMArch,
|
arch::MMArch,
|
||||||
current_pcb,
|
current_pcb,
|
||||||
filesystem::vfs::io::SeekFrom,
|
driver::base::block::SeekFrom,
|
||||||
kerror,
|
kerror,
|
||||||
libs::align::page_align_up,
|
libs::align::page_align_up,
|
||||||
mm::{
|
mm::{
|
||||||
|
@ -7,7 +7,7 @@ use core::{
|
|||||||
use alloc::{boxed::Box, collections::LinkedList, string::String, sync::Arc};
|
use alloc::{boxed::Box, collections::LinkedList, string::String, sync::Arc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
driver::uart::uart::{c_uart_send_str, UartPort},
|
driver::uart::uart_device::{c_uart_send_str, UartPort},
|
||||||
include::bindings::bindings::{
|
include::bindings::bindings::{
|
||||||
scm_buffer_info_t, video_frame_buffer_info, video_reinitialize, video_set_refresh_target,
|
scm_buffer_info_t, video_frame_buffer_info, video_reinitialize, video_set_refresh_target,
|
||||||
},
|
},
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
driver::uart::uart::{c_uart_send, c_uart_send_str, UartPort},
|
driver::uart::uart_device::{c_uart_send, c_uart_send_str, UartPort},
|
||||||
include::bindings::bindings::video_frame_buffer_info,
|
include::bindings::bindings::video_frame_buffer_info,
|
||||||
kinfo,
|
kinfo,
|
||||||
libs::{lib_ui::font::FONT_8x16, spinlock::SpinLock},
|
libs::{lib_ui::font::FONT_8x16, spinlock::SpinLock},
|
||||||
|
@ -4,7 +4,7 @@ use core::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
driver::uart::uart::{c_uart_send, UartPort},
|
driver::uart::uart_device::{c_uart_send, UartPort},
|
||||||
include::bindings::bindings::video_frame_buffer_info,
|
include::bindings::bindings::video_frame_buffer_info,
|
||||||
syscall::SystemError,
|
syscall::SystemError,
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,7 @@ use core::mem::size_of;
|
|||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
use crate::{filesystem::vfs::io::SeekFrom, syscall::SystemError};
|
use crate::{driver::base::block::SeekFrom, syscall::SystemError};
|
||||||
|
|
||||||
/// @brief 本模块用于为数组提供游标的功能,以简化其操作。
|
/// @brief 本模块用于为数组提供游标的功能,以简化其操作。
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -34,7 +34,8 @@
|
|||||||
|
|
||||||
#include <driver/interrupt/apic/apic_timer.h>
|
#include <driver/interrupt/apic/apic_timer.h>
|
||||||
|
|
||||||
extern int rs_tty_init();
|
extern int rs_device_init();
|
||||||
|
extern int rs_tty_init();
|
||||||
extern void rs_softirq_init();
|
extern void rs_softirq_init();
|
||||||
extern void rs_mm_init();
|
extern void rs_mm_init();
|
||||||
|
|
||||||
@ -141,10 +142,9 @@ void system_initialize()
|
|||||||
io_mfence();
|
io_mfence();
|
||||||
|
|
||||||
rs_jiffies_init();
|
rs_jiffies_init();
|
||||||
io_mfence();
|
|
||||||
|
|
||||||
io_mfence();
|
io_mfence();
|
||||||
vfs_init();
|
vfs_init();
|
||||||
|
rs_device_init();
|
||||||
rs_tty_init();
|
rs_tty_init();
|
||||||
io_mfence();
|
io_mfence();
|
||||||
// 由于进程管理模块依赖于文件系统,因此必须在文件系统初始化完毕后再初始化进程管理模块
|
// 由于进程管理模块依赖于文件系统,因此必须在文件系统初始化完毕后再初始化进程管理模块
|
||||||
|
@ -3,7 +3,7 @@ use core::{fmt::Debug, ptr::null};
|
|||||||
use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec};
|
use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
filesystem::vfs::io::SeekFrom,
|
driver::base::block::SeekFrom,
|
||||||
filesystem::vfs::{
|
filesystem::vfs::{
|
||||||
file::{File, FileMode},
|
file::{File, FileMode},
|
||||||
ROOT_INODE,
|
ROOT_INODE,
|
||||||
|
@ -7,7 +7,7 @@ use num_traits::{FromPrimitive, ToPrimitive};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{cpu::cpu_reset, MMArch},
|
arch::{cpu::cpu_reset, MMArch},
|
||||||
filesystem::vfs::io::SeekFrom,
|
driver::base::block::SeekFrom,
|
||||||
filesystem::vfs::{
|
filesystem::vfs::{
|
||||||
fcntl::FcntlCommand,
|
fcntl::FcntlCommand,
|
||||||
file::FileMode,
|
file::FileMode,
|
||||||
|
25
user/apps/test_uart/Makefile
Normal file
25
user/apps/test_uart/Makefile
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
CC=$(DragonOS_GCC)/x86_64-elf-gcc
|
||||||
|
LD=ld
|
||||||
|
OBJCOPY=objcopy
|
||||||
|
# 修改这里,把它改为你的relibc的sysroot路径
|
||||||
|
RELIBC_OPT=$(DADK_BUILD_CACHE_DIR_RELIBC_0_1_0)
|
||||||
|
CFLAGS=-I $(RELIBC_OPT)/include -D__dragonos__
|
||||||
|
|
||||||
|
tmp_output_dir=$(ROOT_PATH)/bin/tmp/user
|
||||||
|
output_dir=$(DADK_BUILD_CACHE_DIR_TEST_UART_0_1_0)
|
||||||
|
|
||||||
|
LIBC_OBJS:=$(shell find $(RELIBC_OPT)/lib -name "*.o" | sort )
|
||||||
|
LIBC_OBJS+=$(RELIBC_OPT)/lib/libc.a
|
||||||
|
|
||||||
|
all: main.o
|
||||||
|
mkdir -p $(tmp_output_dir)
|
||||||
|
|
||||||
|
$(LD) -b elf64-x86-64 -z muldefs -o $(tmp_output_dir)/test_uart $(shell find . -name "*.o") $(LIBC_OBJS) -T link.lds
|
||||||
|
|
||||||
|
$(OBJCOPY) -I elf64-x86-64 -R ".eh_frame" -R ".comment" -O elf64-x86-64 $(tmp_output_dir)/test_uart $(output_dir)/test_uart.elf
|
||||||
|
mv $(output_dir)/test_uart.elf $(output_dir)/test_uart
|
||||||
|
main.o: main.c
|
||||||
|
$(CC) $(CFLAGS) -c main.c -o main.o
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o
|
239
user/apps/test_uart/link.lds
Normal file
239
user/apps/test_uart/link.lds
Normal file
@ -0,0 +1,239 @@
|
|||||||
|
/* Script for -z combreloc */
|
||||||
|
/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
|
||||||
|
Copying and distribution of this script, with or without modification,
|
||||||
|
are permitted in any medium without royalty provided the copyright
|
||||||
|
notice and this notice are preserved. */
|
||||||
|
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
|
||||||
|
"elf64-x86-64")
|
||||||
|
OUTPUT_ARCH(i386:x86-64)
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* Read-only sections, merged into text segment: */
|
||||||
|
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x20000000) + SIZEOF_HEADERS;
|
||||||
|
.interp : { *(.interp) }
|
||||||
|
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
||||||
|
.hash : { *(.hash) }
|
||||||
|
.gnu.hash : { *(.gnu.hash) }
|
||||||
|
.dynsym : { *(.dynsym) }
|
||||||
|
.dynstr : { *(.dynstr) }
|
||||||
|
.gnu.version : { *(.gnu.version) }
|
||||||
|
.gnu.version_d : { *(.gnu.version_d) }
|
||||||
|
.gnu.version_r : { *(.gnu.version_r) }
|
||||||
|
.rela.dyn :
|
||||||
|
{
|
||||||
|
*(.rela.init)
|
||||||
|
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
||||||
|
*(.rela.fini)
|
||||||
|
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
||||||
|
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
||||||
|
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
||||||
|
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
||||||
|
*(.rela.ctors)
|
||||||
|
*(.rela.dtors)
|
||||||
|
*(.rela.got)
|
||||||
|
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||||
|
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
|
||||||
|
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
|
||||||
|
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
|
||||||
|
*(.rela.ifunc)
|
||||||
|
}
|
||||||
|
.rela.plt :
|
||||||
|
{
|
||||||
|
*(.rela.plt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_start = .);
|
||||||
|
*(.rela.iplt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_end = .);
|
||||||
|
}
|
||||||
|
. = ALIGN(CONSTANT (MAXPAGESIZE));
|
||||||
|
.init :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.init)))
|
||||||
|
}
|
||||||
|
.plt : { *(.plt) *(.iplt) }
|
||||||
|
.plt.got : { *(.plt.got) }
|
||||||
|
.plt.sec : { *(.plt.sec) }
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||||
|
*(.text.exit .text.exit.*)
|
||||||
|
*(.text.startup .text.startup.*)
|
||||||
|
*(.text.hot .text.hot.*)
|
||||||
|
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||||
|
/* .gnu.warning sections are handled specially by elf.em. */
|
||||||
|
*(.gnu.warning)
|
||||||
|
}
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.fini)))
|
||||||
|
}
|
||||||
|
PROVIDE (__etext = .);
|
||||||
|
PROVIDE (_etext = .);
|
||||||
|
PROVIDE (etext = .);
|
||||||
|
. = ALIGN(CONSTANT (MAXPAGESIZE));
|
||||||
|
/* Adjust the address for the rodata segment. We want to adjust up to
|
||||||
|
the same address within the page on the next page up. */
|
||||||
|
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
|
||||||
|
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||||
|
.rodata1 : { *(.rodata1) }
|
||||||
|
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
|
||||||
|
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
|
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
|
||||||
|
/* These sections are generated by the Sun/Oracle C++ compiler. */
|
||||||
|
.exception_ranges : ONLY_IF_RO { *(.exception_ranges*) }
|
||||||
|
/* Adjust the address for the data segment. We want to adjust up to
|
||||||
|
the same address within the page on the next page up. */
|
||||||
|
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
|
||||||
|
/* Exception handling */
|
||||||
|
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
|
||||||
|
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
|
||||||
|
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.exception_ranges : ONLY_IF_RW { *(.exception_ranges*) }
|
||||||
|
/* Thread Local Storage sections */
|
||||||
|
.tdata :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__tdata_start = .);
|
||||||
|
*(.tdata .tdata.* .gnu.linkonce.td.*)
|
||||||
|
}
|
||||||
|
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
|
||||||
|
.preinit_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||||
|
}
|
||||||
|
.init_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__init_array_start = .);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||||
|
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
|
||||||
|
PROVIDE_HIDDEN (__init_array_end = .);
|
||||||
|
}
|
||||||
|
.fini_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||||
|
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
||||||
|
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||||
|
}
|
||||||
|
.ctors :
|
||||||
|
{
|
||||||
|
/* gcc uses crtbegin.o to find the start of
|
||||||
|
the constructors, so we make sure it is
|
||||||
|
first. Because this is a wildcard, it
|
||||||
|
doesn't matter if the user does not
|
||||||
|
actually link against crtbegin.o; the
|
||||||
|
linker won't look for a file to match a
|
||||||
|
wildcard. The wildcard also means that it
|
||||||
|
doesn't matter which directory crtbegin.o
|
||||||
|
is in. */
|
||||||
|
KEEP (*crtbegin.o(.ctors))
|
||||||
|
KEEP (*crtbegin?.o(.ctors))
|
||||||
|
/* We don't want to include the .ctor section from
|
||||||
|
the crtend.o file until after the sorted ctors.
|
||||||
|
The .ctor section from the crtend file contains the
|
||||||
|
end of ctors marker and it must be last */
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
}
|
||||||
|
.dtors :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*crtbegin?.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
}
|
||||||
|
.jcr : { KEEP (*(.jcr)) }
|
||||||
|
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
|
||||||
|
.dynamic : { *(.dynamic) }
|
||||||
|
.got : { *(.got) *(.igot) }
|
||||||
|
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
|
||||||
|
.got.plt : { *(.got.plt) *(.igot.plt) }
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
*(.data .data.* .gnu.linkonce.d.*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
}
|
||||||
|
.data1 : { *(.data1) }
|
||||||
|
_edata = .; PROVIDE (edata = .);
|
||||||
|
. = .;
|
||||||
|
__bss_start = .;
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||||
|
*(COMMON)
|
||||||
|
/* Align here to ensure that the .bss section occupies space up to
|
||||||
|
_end. Align after .bss to ensure correct alignment even if the
|
||||||
|
.bss section disappears because there are no input sections.
|
||||||
|
FIXME: Why do we need it? When there is no .bss section, we do not
|
||||||
|
pad the .data section. */
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
.lbss :
|
||||||
|
{
|
||||||
|
*(.dynlbss)
|
||||||
|
*(.lbss .lbss.* .gnu.linkonce.lb.*)
|
||||||
|
*(LARGE_COMMON)
|
||||||
|
}
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
. = SEGMENT_START("ldata-segment", .);
|
||||||
|
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
|
{
|
||||||
|
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
|
||||||
|
}
|
||||||
|
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
|
{
|
||||||
|
*(.ldata .ldata.* .gnu.linkonce.l.*)
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
_end = .; PROVIDE (end = .);
|
||||||
|
. = DATA_SEGMENT_END (.);
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
.comment 0 : { *(.comment) }
|
||||||
|
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
|
||||||
|
/* DWARF debug sections.
|
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning
|
||||||
|
of the section so we begin them at 0. */
|
||||||
|
/* DWARF 1 */
|
||||||
|
.debug 0 : { *(.debug) }
|
||||||
|
.line 0 : { *(.line) }
|
||||||
|
/* GNU DWARF 1 extensions */
|
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||||
|
/* DWARF 1.1 and DWARF 2 */
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
/* DWARF 2 */
|
||||||
|
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
|
||||||
|
.debug_frame 0 : { *(.debug_frame) }
|
||||||
|
.debug_str 0 : { *(.debug_str) }
|
||||||
|
.debug_loc 0 : { *(.debug_loc) }
|
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||||
|
/* SGI/MIPS DWARF 2 extensions */
|
||||||
|
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||||
|
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||||
|
.debug_typenames 0 : { *(.debug_typenames) }
|
||||||
|
.debug_varnames 0 : { *(.debug_varnames) }
|
||||||
|
/* DWARF 3 */
|
||||||
|
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||||
|
.debug_ranges 0 : { *(.debug_ranges) }
|
||||||
|
/* DWARF Extension. */
|
||||||
|
.debug_macro 0 : { *(.debug_macro) }
|
||||||
|
.debug_addr 0 : { *(.debug_addr) }
|
||||||
|
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
|
||||||
|
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
|
||||||
|
}
|
32
user/apps/test_uart/main.c
Normal file
32
user/apps/test_uart/main.c
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// 打开设备文件
|
||||||
|
int fd = open("/dev/char/uart:1088", O_WRONLY | O_NONBLOCK);
|
||||||
|
char buf[1] = {0};
|
||||||
|
int n;
|
||||||
|
memset(buf, 0, 1);
|
||||||
|
while (1) {
|
||||||
|
n = read(fd, buf, 1);
|
||||||
|
close(fd);
|
||||||
|
fd = open("/dev/char/uart:1088", O_WRONLY | O_NONBLOCK);
|
||||||
|
if (n != 0) { // 添加字符串结束符
|
||||||
|
printf("Received: %s\n", buf); // 打印接收到的数据
|
||||||
|
if (buf[0] == 'g') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("fd: %ld", fd);
|
||||||
|
// 写入字符串
|
||||||
|
char *str = "------fuck-----";
|
||||||
|
int len = write(fd, str, strlen(str));
|
||||||
|
printf("len: %ld", len);
|
||||||
|
// 关闭文件
|
||||||
|
close(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
28
user/dadk/config/test_uart-0.1.0.dadk
Normal file
28
user/dadk/config/test_uart-0.1.0.dadk
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"name": "test_uart",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "一个用来测试串口设备能够正常运行的app",
|
||||||
|
"task_type": {
|
||||||
|
"BuildFromSource": {
|
||||||
|
"Local": {
|
||||||
|
"path": "apps/test_uart"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"depends": [
|
||||||
|
{
|
||||||
|
"name": "relibc",
|
||||||
|
"version": "0.1.0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"build": {
|
||||||
|
"build_command": "make"
|
||||||
|
},
|
||||||
|
"install": {
|
||||||
|
"in_dragonos_path": "/bin"
|
||||||
|
},
|
||||||
|
"clean": {
|
||||||
|
"clean_command": "make clean"
|
||||||
|
},
|
||||||
|
"envs": []
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user