linfeng 7c28051e8c
chore: update toolchain version to 2024-11-05 (#1031)
* chore: update toolchain version to 2024-11-05

* update dragon reach to e945c217b3

* update dog to 6f2c0c8f12

---------

Co-authored-by: longjin <longjin@DragonOS.org>
2024-11-11 21:29:15 +08:00

233 lines
8.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use alloc::sync::Arc;
use log::error;
use system_error::SystemError;
use super::{
device::{
device_manager,
device_number::{DeviceNumber, Major},
Device, IdTable, CHARDEVS, DEVMAP,
},
map::{
kobj_map, kobj_unmap, DeviceStruct, DEV_MAJOR_DYN_END, DEV_MAJOR_DYN_EXT_END,
DEV_MAJOR_DYN_EXT_START, DEV_MAJOR_HASH_SIZE, DEV_MAJOR_MAX,
},
};
pub trait CharDevice: Device {
/// Notice buffer对应设备按字节划分使用u8类型
/// Notice offset应该从0开始计数
///
/// @brief: 从设备的第offset个字节开始读取len个byte存放到buf中
/// @parameter offset: 起始字节偏移量
/// @parameter len: 读取字节的数量
/// @parameter buf: 目标数组
/// @return: 如果操作成功,返回操作的长度(单位是字节);否则返回错误码;如果操作异常,但是并没有检查出什么错误,将返回已操作的长度
fn read(&self, len: usize, buf: &mut [u8]) -> Result<usize, SystemError>;
/// @brief: 从设备的第offset个字节开始把buf数组的len个byte写入到设备中
/// @parameter offset: 起始字节偏移量
/// @parameter len: 读取字节的数量
/// @parameter buf: 目标数组
/// @return: 如果操作成功,返回操作的长度(单位是字节);否则返回错误码;如果操作异常,但是并没有检查出什么错误,将返回已操作的长度
fn write(&self, len: usize, buf: &[u8]) -> Result<usize, SystemError>;
/// @brief: 同步信息把所有的dirty数据写回设备 - 待实现
fn sync(&self) -> Result<(), SystemError>;
}
/// @brief 字符设备框架函数集
pub struct CharDevOps;
impl CharDevOps {
/// @brief: 主设备号转下标
/// @parameter: major: 主设备号
/// @return: 返回下标
#[allow(dead_code)]
fn major_to_index(major: Major) -> usize {
return (major.data() % DEV_MAJOR_HASH_SIZE) as usize;
}
/// @brief: 动态获取主设备号
/// @parameter: None
/// @return: 如果成功,返回主设备号,否则,返回错误码
#[allow(dead_code)]
fn find_dynamic_major() -> Result<Major, SystemError> {
let chardevs = CHARDEVS.lock();
// 寻找主设备号为234255的设备
for index in (DEV_MAJOR_DYN_END.data()..DEV_MAJOR_HASH_SIZE).rev() {
if let Some(item) = chardevs.get(index as usize) {
if item.is_empty() {
return Ok(Major::new(index)); // 返回可用的主设备号
}
}
}
// 寻找主设备号在384511的设备
for index in
((DEV_MAJOR_DYN_EXT_END.data() + 1)..(DEV_MAJOR_DYN_EXT_START.data() + 1)).rev()
{
if let Some(chardevss) = chardevs.get(Self::major_to_index(Major::new(index))) {
let mut flag = true;
for item in chardevss {
if item.device_number().major().data() == index {
flag = false;
break;
}
}
if flag {
// 如果数组中不存在主设备号等于index的设备
return Ok(Major::new(index)); // 返回可用的主设备号
}
}
}
return Err(SystemError::EBUSY);
}
/// @brief: 注册设备号,该函数需要指定主设备号
/// @parameter: from: 主设备号
/// count: 次设备号数量
/// name: 字符设备名
/// @return: 如果注册成功,返回设备号,否则,返回错误码
#[allow(dead_code)]
pub fn register_chardev_region(
from: DeviceNumber,
count: u32,
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: u32,
count: u32,
name: &'static str,
) -> Result<DeviceNumber, SystemError> {
Self::__register_chardev_region(
DeviceNumber::new(Major::UNNAMED_MAJOR, baseminor),
count,
name,
)
}
/// @brief: 注册设备号
/// @parameter: device_number: 设备号主设备号如果为0则动态分配
/// minorct: 次设备号数量
/// name: 字符设备名
/// @return: 如果注册成功,返回设备号,否则,返回错误码
fn __register_chardev_region(
device_number: DeviceNumber,
minorct: u32,
name: &'static str,
) -> Result<DeviceNumber, SystemError> {
let mut major = device_number.major();
let baseminor = device_number.minor();
if major >= DEV_MAJOR_MAX {
error!(
"DEV {} major requested {:?} is greater than the maximum {}\n",
name,
major,
DEV_MAJOR_MAX.data() - 1
);
}
if minorct > DeviceNumber::MINOR_MASK + 1 - baseminor {
error!("DEV {} minor range requested ({}-{}) is out of range of maximum range ({}-{}) for a single major\n",
name, baseminor, baseminor + minorct - 1, 0, DeviceNumber::MINOR_MASK);
}
let chardev = DeviceStruct::new(DeviceNumber::new(major, baseminor), minorct, name);
if major == Major::UNNAMED_MAJOR {
// 如果主设备号为0,则自动分配主设备号
major = Self::find_dynamic_major().expect("Find synamic major error.\n");
}
if let Some(items) = CHARDEVS.lock().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) {
core::cmp::Ordering::Less => continue,
core::cmp::Ordering::Greater => {
break; // 大于则向后插入
}
core::cmp::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(DeviceNumber::new(major, baseminor));
}
/// @brief: 注销设备号
/// @parameter: major: 主设备号如果为0动态分配
/// baseminor: 起始次设备号
/// minorct: 次设备号数量
/// @return: 如果注销成功,返回(),否则,返回错误码
fn __unregister_chardev_region(
device_number: DeviceNumber,
minorct: u32,
) -> Result<(), SystemError> {
if let Some(items) = CHARDEVS
.lock()
.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,
) -> Result<(), SystemError> {
if id_table.device_number().data() == 0 {
error!("Device number can't be 0!\n");
}
device_manager().add_device(cdev.clone())?;
kobj_map(
DEVMAP.clone(),
id_table.device_number(),
range,
cdev.clone(),
);
return Ok(());
}
/// @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);
}
}