1 use super::{
2     device::{mkdev, DeviceNumber, KObject},
3     map::{kobj_map, kobj_unmap, LockedKObjMap},
4 };
5 use crate::{filesystem::vfs::IndexNode, kerror, libs::spinlock::SpinLock, syscall::SystemError};
6 use alloc::{sync::Arc, vec::Vec};
7 use core::cmp::Ordering;
8 
9 const CHARDEV_MAJOR_HASH_SIZE: usize = 255;
10 const CHARDEV_MAJOR_MAX: usize = 512;
11 const MINOR_BITS: usize = 20;
12 const MINOR_MASK: usize = 1 << MINOR_BITS - 1;
13 /* Marks the bottom of the first segment of free char majors */
14 const CHARDEV_MAJOR_DYN_END: usize = 234;
15 /* Marks the top and bottom of the second segment of free char majors */
16 const CHARDEV_MAJOR_DYN_EXT_START: usize = 511;
17 const CHARDEV_MAJOR_DYN_EXT_END: usize = 384;
18 
19 lazy_static! {
20     // 全局字符设备号管理实例
21     pub static ref CHARDEVS: Arc<LockedChrDevs> = Arc::new(LockedChrDevs::default());
22 
23     // 全局字符设备管理实例
24     pub static ref CDEVMAP: Arc<LockedKObjMap> = Arc::new(LockedKObjMap::default());
25 }
26 
27 pub trait CharDevice: KObject {
28     /// @brief: 打开设备
29     /// @parameter: file: devfs inode
30     /// @return: 打开成功,返回OK(()),失败,返回错误代码
open(&self, file: Arc<dyn IndexNode>) -> Result<(), SystemError>31     fn open(&self, file: Arc<dyn IndexNode>) -> Result<(), SystemError>;
32 
33     /// @brief: 关闭设备
34     /// @parameter: file: devfs inode
35     /// @return: 关闭成功,返回OK(()),失败,返回错误代码
close(&self, file: Arc<dyn IndexNode>) -> Result<(), SystemError>36     fn close(&self, file: Arc<dyn IndexNode>) -> Result<(), SystemError>;
37 }
38 
39 // 管理字符设备号的map(加锁)
40 pub struct LockedChrDevs(SpinLock<ChrDevs>);
41 
42 impl Default for LockedChrDevs {
default() -> Self43     fn default() -> Self {
44         LockedChrDevs(SpinLock::new(ChrDevs::default()))
45     }
46 }
47 
48 // 管理字符设备号的map
49 #[derive(Debug)]
50 struct ChrDevs(Vec<Vec<CharDeviceStruct>>);
51 
52 impl Default for ChrDevs {
default() -> Self53     fn default() -> Self {
54         ChrDevs(vec![Vec::new(); CHARDEV_MAJOR_HASH_SIZE])
55     }
56 }
57 
58 // 字符设备在系统中的实例,devfs通过该结构与实际字符设备进行联系
59 #[allow(dead_code)]
60 #[derive(Debug, Clone)]
61 pub struct CharDeviceStruct {
62     dev_t: DeviceNumber, //起始设备号
63     minorct: usize,      // 次设备号数量
64     name: &'static str,  //字符设备名
65 }
66 
67 impl CharDeviceStruct {
68     /// @brief: 创建实例
69     /// @parameter: dev_t: 设备号
70     ///             minorct: 次设备号数量
71     ///             name: 字符设备名
72     ///             char: 字符设备实例
73     /// @return: 实例
74     ///
75     #[allow(dead_code)]
new(dev_t: DeviceNumber, minorct: usize, name: &'static str) -> Self76     pub fn new(dev_t: DeviceNumber, minorct: usize, name: &'static str) -> Self {
77         Self {
78             dev_t,
79             minorct,
80             name,
81         }
82     }
83 
84     /// @brief: 获取起始次设备号
85     /// @parameter: None
86     /// @return: 起始设备号
87     ///
88     #[allow(dead_code)]
device_number(&self) -> DeviceNumber89     pub fn device_number(&self) -> DeviceNumber {
90         self.dev_t
91     }
92 
93     /// @brief: 获取起始次设备号
94     /// @parameter: None
95     /// @return: 起始设备号
96     ///
97     #[allow(dead_code)]
base_minor(&self) -> usize98     pub fn base_minor(&self) -> usize {
99         self.dev_t.minor()
100     }
101 
102     /// @brief: 获取次设备号数量
103     /// @parameter: None
104     /// @return: 次设备号数量
105     #[allow(dead_code)]
minorct(&self) -> usize106     pub fn minorct(&self) -> usize {
107         self.minorct
108     }
109 }
110 
111 /// @brief 字符设备框架函数集
112 pub struct CharDevOps;
113 
114 impl CharDevOps {
115     /// @brief: 主设备号转下标
116     /// @parameter: major: 主设备号
117     /// @return: 返回下标
118     #[allow(dead_code)]
major_to_index(major: usize) -> usize119     fn major_to_index(major: usize) -> usize {
120         return major % CHARDEV_MAJOR_HASH_SIZE;
121     }
122 
123     /// @brief: 动态获取主设备号
124     /// @parameter: None
125     /// @return: 如果成功,返回主设备号,否则,返回错误码
126     #[allow(dead_code)]
find_dynamic_major() -> Result<usize, SystemError>127     fn find_dynamic_major() -> Result<usize, SystemError> {
128         let chardevs = CHARDEVS.0.lock();
129         // 寻找主设备号为234~255的设备
130         for index in (CHARDEV_MAJOR_DYN_END..CHARDEV_MAJOR_HASH_SIZE).rev() {
131             if let Some(item) = chardevs.0.get(index) {
132                 if item.is_empty() {
133                     return Ok(index); // 返回可用的主设备号
134                 }
135             }
136         }
137         // 寻找主设备号在384~511的设备
138         for index in (CHARDEV_MAJOR_DYN_EXT_END + 1..CHARDEV_MAJOR_DYN_EXT_START + 1).rev() {
139             if let Some(chardevss) = chardevs.0.get(Self::major_to_index(index)) {
140                 let mut flag = true;
141                 for item in chardevss {
142                     if item.device_number().major() == index {
143                         flag = false;
144                         break;
145                     }
146                 }
147                 if flag {
148                     // 如果数组中不存在主设备号等于index的设备
149                     return Ok(index); // 返回可用的主设备号
150                 }
151             }
152         }
153         return Err(SystemError::EBUSY);
154     }
155 
156     /// @brief: 注册设备号,该函数需要指定主设备号
157     /// @parameter: from: 主设备号
158     ///             count: 次设备号数量
159     ///             name: 字符设备名
160     /// @return: 如果注册成功,返回设备号,否则,返回错误码
161     #[allow(dead_code)]
register_chardev_region( from: DeviceNumber, count: usize, name: &'static str, ) -> Result<DeviceNumber, SystemError>162     pub fn register_chardev_region(
163         from: DeviceNumber,
164         count: usize,
165         name: &'static str,
166     ) -> Result<DeviceNumber, SystemError> {
167         Self::__register_chardev_region(from, count, name)
168     }
169 
170     /// @brief: 注册设备号,该函数自动分配主设备号
171     /// @parameter: baseminor: 主设备号
172     ///             count: 次设备号数量
173     ///             name: 字符设备名
174     /// @return: 如果注册成功,返回,否则,返回false
175     #[allow(dead_code)]
alloc_chardev_region( baseminor: usize, count: usize, name: &'static str, ) -> Result<DeviceNumber, SystemError>176     pub fn alloc_chardev_region(
177         baseminor: usize,
178         count: usize,
179         name: &'static str,
180     ) -> Result<DeviceNumber, SystemError> {
181         Self::__register_chardev_region(mkdev(0, baseminor), count, name)
182     }
183 
184     /// @brief: 注册设备号
185     /// @parameter: device_number: 设备号,主设备号如果为0,则动态分配
186     ///             minorct: 次设备号数量
187     ///             name: 字符设备名
188     /// @return: 如果注册成功,返回设备号,否则,返回错误码
__register_chardev_region( device_number: DeviceNumber, minorct: usize, name: &'static str, ) -> Result<DeviceNumber, SystemError>189     fn __register_chardev_region(
190         device_number: DeviceNumber,
191         minorct: usize,
192         name: &'static str,
193     ) -> Result<DeviceNumber, SystemError> {
194         let mut major = device_number.major();
195         let baseminor = device_number.minor();
196         if major >= CHARDEV_MAJOR_MAX {
197             kerror!(
198                 "CHARDEV {} major requested {} is greater than the maximum {}\n",
199                 name,
200                 major,
201                 CHARDEV_MAJOR_MAX - 1
202             );
203         }
204         if minorct > MINOR_MASK + 1 - baseminor {
205             kerror!("CHARDEV {} minor range requested ({}-{}) is out of range of maximum range ({}-{}) for a single major\n",
206                 name, baseminor, baseminor + minorct - 1, 0, MINOR_MASK);
207         }
208         let chardev = CharDeviceStruct::new(mkdev(major, baseminor), minorct, name);
209         if major == 0 {
210             // 如果主设备号为0,则自动分配主设备号
211             major = Self::find_dynamic_major().expect("Find synamic major error.\n");
212         }
213         if let Some(items) = CHARDEVS.0.lock().0.get_mut(Self::major_to_index(major)) {
214             let mut insert_index: usize = 0;
215             for (index, item) in items.iter().enumerate() {
216                 insert_index = index;
217                 match item.device_number().major().cmp(&major) {
218                     Ordering::Less => continue,
219                     Ordering::Greater => {
220                         break; // 大于则向后插入
221                     }
222                     Ordering::Equal => {
223                         if item.device_number().minor() + item.minorct() <= baseminor {
224                             continue; // 下一个主设备号大于或者次设备号大于被插入的次设备号最大值
225                         }
226                         if item.base_minor() >= baseminor + minorct {
227                             break; // 在此处插入
228                         }
229                         return Err(SystemError::EBUSY); // 存在重合的次设备号
230                     }
231                 }
232             }
233             items.insert(insert_index, chardev);
234         }
235         return Ok(mkdev(major, baseminor));
236     }
237 
238     /// @brief: 注销设备号
239     /// @parameter: major: 主设备号,如果为0,动态分配
240     ///             baseminor: 起始次设备号
241     ///             minorct: 次设备号数量
242     /// @return: 如果注销成功,返回(),否则,返回错误码
__unregister_chardev_region( device_number: DeviceNumber, minorct: usize, ) -> Result<(), SystemError>243     fn __unregister_chardev_region(
244         device_number: DeviceNumber,
245         minorct: usize,
246     ) -> Result<(), SystemError> {
247         if let Some(items) = CHARDEVS
248             .0
249             .lock()
250             .0
251             .get_mut(Self::major_to_index(device_number.major()))
252         {
253             for (index, item) in items.iter().enumerate() {
254                 if item.device_number() == device_number && item.minorct() == minorct {
255                     // 设备号和数量都相等
256                     items.remove(index);
257                     return Ok(());
258                 }
259             }
260         }
261         return Err(SystemError::EBUSY);
262     }
263 
264     /// @brief: 字符设备注册
265     /// @parameter: cdev: 字符设备实例
266     ///             dev_t: 字符设备号
267     ///             range: 次设备号范围
268     /// @return: none
269     #[allow(dead_code)]
cdev_add(cdev: Arc<dyn CharDevice>, dev_t: DeviceNumber, range: usize)270     pub fn cdev_add(cdev: Arc<dyn CharDevice>, dev_t: DeviceNumber, range: usize) {
271         if Into::<usize>::into(dev_t) == 0 {
272             kerror!("Device number can't be 0!\n");
273         }
274         kobj_map(CDEVMAP.clone(), dev_t, range, cdev);
275     }
276 
277     /// @brief: 字符设备注销
278     /// @parameter: dev_t: 字符设备号
279     ///             range: 次设备号范围
280     /// @return: none
281     #[allow(dead_code)]
cdev_del(dev_t: DeviceNumber, range: usize)282     pub fn cdev_del(dev_t: DeviceNumber, range: usize) {
283         kobj_unmap(CDEVMAP.clone(), dev_t, range);
284     }
285 }
286