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