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