xref: /DragonOS/kernel/src/driver/base/char/mod.rs (revision 83ed0ebc293d5a10245089f627f52770fd5b9dd4)
1 use alloc::sync::Arc;
2 
3 use crate::{kerror, syscall::SystemError};
4 
5 use super::{
6     device::{device_manager, mkdev, Device, DeviceNumber, IdTable, CHARDEVS, DEVMAP},
7     map::{
8         kobj_map, kobj_unmap, DeviceStruct, DEV_MAJOR_DYN_END, DEV_MAJOR_DYN_EXT_END,
9         DEV_MAJOR_DYN_EXT_START, DEV_MAJOR_HASH_SIZE, DEV_MAJOR_MAX, MINOR_MASK,
10     },
11 };
12 
13 pub trait CharDevice: Device {
14     /// Notice buffer对应设备按字节划分,使用u8类型
15     /// Notice offset应该从0开始计数
16 
17     /// @brief: 从设备的第offset个字节开始,读取len个byte,存放到buf中
18     /// @parameter offset: 起始字节偏移量
19     /// @parameter len: 读取字节的数量
20     /// @parameter buf: 目标数组
21     /// @return: 如果操作成功,返回操作的长度(单位是字节);否则返回错误码;如果操作异常,但是并没有检查出什么错误,将返回已操作的长度
22     fn read(&self, len: usize, buf: &mut [u8]) -> Result<usize, SystemError>;
23 
24     /// @brief: 从设备的第offset个字节开始,把buf数组的len个byte,写入到设备中
25     /// @parameter offset: 起始字节偏移量
26     /// @parameter len: 读取字节的数量
27     /// @parameter buf: 目标数组
28     /// @return: 如果操作成功,返回操作的长度(单位是字节);否则返回错误码;如果操作异常,但是并没有检查出什么错误,将返回已操作的长度
29     fn write(&self, len: usize, buf: &[u8]) -> Result<usize, SystemError>;
30 
31     /// @brief: 同步信息,把所有的dirty数据写回设备 - 待实现
32     fn sync(&self) -> Result<(), SystemError>;
33 }
34 
35 /// @brief 字符设备框架函数集
36 pub struct CharDevOps;
37 
38 impl CharDevOps {
39     /// @brief: 主设备号转下标
40     /// @parameter: major: 主设备号
41     /// @return: 返回下标
42     #[allow(dead_code)]
43     fn major_to_index(major: usize) -> usize {
44         return major % DEV_MAJOR_HASH_SIZE;
45     }
46 
47     /// @brief: 动态获取主设备号
48     /// @parameter: None
49     /// @return: 如果成功,返回主设备号,否则,返回错误码
50     #[allow(dead_code)]
51     fn find_dynamic_major() -> Result<usize, SystemError> {
52         let chardevs = CHARDEVS.lock();
53         // 寻找主设备号为234~255的设备
54         for index in (DEV_MAJOR_DYN_END..DEV_MAJOR_HASH_SIZE).rev() {
55             if let Some(item) = chardevs.get(index) {
56                 if item.is_empty() {
57                     return Ok(index); // 返回可用的主设备号
58                 }
59             }
60         }
61         // 寻找主设备号在384~511的设备
62         for index in (DEV_MAJOR_DYN_EXT_END + 1..DEV_MAJOR_DYN_EXT_START + 1).rev() {
63             if let Some(chardevss) = chardevs.get(Self::major_to_index(index)) {
64                 let mut flag = true;
65                 for item in chardevss {
66                     if item.device_number().major() == index {
67                         flag = false;
68                         break;
69                     }
70                 }
71                 if flag {
72                     // 如果数组中不存在主设备号等于index的设备
73                     return Ok(index); // 返回可用的主设备号
74                 }
75             }
76         }
77         return Err(SystemError::EBUSY);
78     }
79 
80     /// @brief: 注册设备号,该函数需要指定主设备号
81     /// @parameter: from: 主设备号
82     ///             count: 次设备号数量
83     ///             name: 字符设备名
84     /// @return: 如果注册成功,返回设备号,否则,返回错误码
85     #[allow(dead_code)]
86     pub fn register_chardev_region(
87         from: DeviceNumber,
88         count: usize,
89         name: &'static str,
90     ) -> Result<DeviceNumber, SystemError> {
91         Self::__register_chardev_region(from, count, name)
92     }
93 
94     /// @brief: 注册设备号,该函数自动分配主设备号
95     /// @parameter: baseminor: 次设备号
96     ///             count: 次设备号数量
97     ///             name: 字符设备名
98     /// @return: 如果注册成功,返回,否则,返回false
99     #[allow(dead_code)]
100     pub fn alloc_chardev_region(
101         baseminor: usize,
102         count: usize,
103         name: &'static str,
104     ) -> Result<DeviceNumber, SystemError> {
105         Self::__register_chardev_region(mkdev(0, baseminor), count, name)
106     }
107 
108     /// @brief: 注册设备号
109     /// @parameter: device_number: 设备号,主设备号如果为0,则动态分配
110     ///             minorct: 次设备号数量
111     ///             name: 字符设备名
112     /// @return: 如果注册成功,返回设备号,否则,返回错误码
113     fn __register_chardev_region(
114         device_number: DeviceNumber,
115         minorct: usize,
116         name: &'static str,
117     ) -> Result<DeviceNumber, SystemError> {
118         let mut major = device_number.major();
119         let baseminor = device_number.minor();
120         if major >= DEV_MAJOR_MAX {
121             kerror!(
122                 "DEV {} major requested {} is greater than the maximum {}\n",
123                 name,
124                 major,
125                 DEV_MAJOR_MAX - 1
126             );
127         }
128         if minorct > MINOR_MASK + 1 - baseminor {
129             kerror!("DEV {} minor range requested ({}-{}) is out of range of maximum range ({}-{}) for a single major\n",
130                 name, baseminor, baseminor + minorct - 1, 0, MINOR_MASK);
131         }
132         let chardev = DeviceStruct::new(mkdev(major, baseminor), minorct, name);
133         if major == 0 {
134             // 如果主设备号为0,则自动分配主设备号
135             major = Self::find_dynamic_major().expect("Find synamic major error.\n");
136         }
137         if let Some(items) = CHARDEVS.lock().get_mut(Self::major_to_index(major)) {
138             let mut insert_index: usize = 0;
139             for (index, item) in items.iter().enumerate() {
140                 insert_index = index;
141                 match item.device_number().major().cmp(&major) {
142                     core::cmp::Ordering::Less => continue,
143                     core::cmp::Ordering::Greater => {
144                         break; // 大于则向后插入
145                     }
146                     core::cmp::Ordering::Equal => {
147                         if item.device_number().minor() + item.minorct() <= baseminor {
148                             continue; // 下一个主设备号大于或者次设备号大于被插入的次设备号最大值
149                         }
150                         if item.base_minor() >= baseminor + minorct {
151                             break; // 在此处插入
152                         }
153                         return Err(SystemError::EBUSY); // 存在重合的次设备号
154                     }
155                 }
156             }
157             items.insert(insert_index, chardev);
158         }
159         return Ok(mkdev(major, baseminor));
160     }
161 
162     /// @brief: 注销设备号
163     /// @parameter: major: 主设备号,如果为0,动态分配
164     ///             baseminor: 起始次设备号
165     ///             minorct: 次设备号数量
166     /// @return: 如果注销成功,返回(),否则,返回错误码
167     fn __unregister_chardev_region(
168         device_number: DeviceNumber,
169         minorct: usize,
170     ) -> Result<(), SystemError> {
171         if let Some(items) = CHARDEVS
172             .lock()
173             .get_mut(Self::major_to_index(device_number.major()))
174         {
175             for (index, item) in items.iter().enumerate() {
176                 if item.device_number() == device_number && item.minorct() == minorct {
177                     // 设备号和数量都相等
178                     items.remove(index);
179                     return Ok(());
180                 }
181             }
182         }
183         return Err(SystemError::EBUSY);
184     }
185 
186     /// @brief: 字符设备注册
187     /// @parameter: cdev: 字符设备实例
188     ///             dev_t: 字符设备号
189     ///             range: 次设备号范围
190     /// @return: none
191     #[allow(dead_code)]
192     pub fn cdev_add(
193         cdev: Arc<dyn CharDevice>,
194         id_table: IdTable,
195         range: usize,
196     ) -> Result<(), SystemError> {
197         if Into::<usize>::into(id_table.device_number()) == 0 {
198             kerror!("Device number can't be 0!\n");
199         }
200         device_manager().add_device(cdev.clone())?;
201         kobj_map(
202             DEVMAP.clone(),
203             id_table.device_number(),
204             range,
205             cdev.clone(),
206         );
207 
208         return Ok(());
209     }
210 
211     /// @brief: 字符设备注销
212     /// @parameter: dev_t: 字符设备号
213     ///             range: 次设备号范围
214     /// @return: none
215     #[allow(dead_code)]
216     pub fn cdev_del(id_table: IdTable, range: usize) {
217         device_manager().remove_device(&id_table);
218         kobj_unmap(DEVMAP.clone(), id_table.device_number(), range);
219     }
220 }
221