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