TingHuang 0663027b11
注册串口设备,创建字符设备框架(#290)
* 按照rust规范修改两个函数名称

* 修改一些函数句柄以符合rust规范

* 添加字符设备相关

* 添加字符设备相关文件

* 添加字符设备驱动框架代码

* 将串口注册

* 规范代码
2023-07-12 12:49:45 +08:00

286 lines
9.9 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 super::{
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;
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 static ref CHARDEVS: Arc<LockedChrDevs> = Arc::new(LockedChrDevs::default());
// 全局字符设备管理实例
pub static ref CDEVMAP: Arc<LockedKObjMap> = Arc::new(LockedKObjMap::default());
}
pub trait CharDevice: KObject {
/// @brief: 打开设备
/// @parameter: file: devfs inode
/// @return: 打开成功返回OK(()),失败,返回错误代码
fn open(&self, file: Arc<dyn IndexNode>) -> Result<(), SystemError>;
/// @brief: 关闭设备
/// @parameter: file: devfs inode
/// @return: 关闭成功返回OK(()),失败,返回错误代码
fn close(&self, file: Arc<dyn IndexNode>) -> 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();
// 寻找主设备号为234255的设备
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); // 返回可用的主设备号
}
}
}
// 寻找主设备号在384511的设备
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);
}
}