1 use alloc::{
2 collections::BTreeMap,
3 string::{String, ToString},
4 sync::{Arc, Weak},
5 };
6
7 use crate::{
8 filesystem::{
9 devfs::{devfs_register, DevFS, DeviceINode},
10 vfs::{file::FileMode, FilePrivateData, FileType, IndexNode, Metadata, ROOT_INODE},
11 },
12 include::bindings::bindings::{textui_putchar, BLACK, WHITE},
13 kerror,
14 libs::rwlock::RwLock,
15 syscall::SystemError,
16 };
17
18 use super::{TtyCore, TtyError, TtyFileFlag, TtyFilePrivateData};
19
20 lazy_static! {
21 /// 所有TTY设备的B树。用于根据名字,找到Arc<TtyDevice>
22 /// TODO: 待设备驱动模型完善,具有类似功能的机制后,删掉这里
23 pub static ref TTY_DEVICES: RwLock<BTreeMap<String, Arc<TtyDevice>>> = RwLock::new(BTreeMap::new());
24 }
25
26 /// @brief TTY设备
27 #[derive(Debug)]
28 pub struct TtyDevice {
29 /// TTY核心
30 core: TtyCore,
31 /// TTY所属的文件系统
32 fs: RwLock<Weak<DevFS>>,
33 /// TTY设备私有信息
34 private_data: RwLock<TtyDevicePrivateData>,
35 }
36
37 #[derive(Debug)]
38 struct TtyDevicePrivateData {
39 /// TTY设备名(如tty1)
40 name: String,
41 /// TTY设备文件的元数据
42 metadata: Metadata,
43 // TODO: 增加指向输出端口连接的设备的指针
44 }
45
46 impl TtyDevice {
new(name: &str) -> Arc<TtyDevice>47 pub fn new(name: &str) -> Arc<TtyDevice> {
48 let result = Arc::new(TtyDevice {
49 core: TtyCore::new(),
50 fs: RwLock::new(Weak::default()),
51 private_data: TtyDevicePrivateData::new(name),
52 });
53 // 默认开启输入回显
54 result.core.enable_echo();
55 return result;
56 }
57
58 /// @brief 判断文件私有信息是否为TTY文件的私有信息
59 #[inline]
verify_file_private_data<'a>( &self, private_data: &'a mut FilePrivateData, ) -> Result<&'a mut TtyFilePrivateData, SystemError>60 fn verify_file_private_data<'a>(
61 &self,
62 private_data: &'a mut FilePrivateData,
63 ) -> Result<&'a mut TtyFilePrivateData, SystemError> {
64 if let FilePrivateData::Tty(t) = private_data {
65 return Ok(t);
66 }
67 return Err(SystemError::EIO);
68 }
69
70 /// @brief 获取TTY设备名
71 #[inline]
name(&self) -> String72 pub fn name(&self) -> String {
73 return self.private_data.read().name.clone();
74 }
75
76 /// @brief 检查TTY文件的读写参数是否合法
77 #[inline]
check_rw_param(&self, len: usize, buf: &[u8]) -> Result<(), SystemError>78 pub fn check_rw_param(&self, len: usize, buf: &[u8]) -> Result<(), SystemError> {
79 if len > buf.len() {
80 return Err(SystemError::EINVAL);
81 }
82 return Ok(());
83 }
84
85 /// @brief 向TTY的输入端口导入数据
input(&self, buf: &[u8]) -> Result<usize, SystemError>86 pub fn input(&self, buf: &[u8]) -> Result<usize, SystemError> {
87 let r: Result<usize, TtyError> = self.core.input(buf, false);
88 if r.is_ok() {
89 return Ok(r.unwrap());
90 }
91
92 let r = r.unwrap_err();
93 match r {
94 TtyError::BufferFull(x) => return Ok(x),
95 TtyError::Closed => return Err(SystemError::ENODEV),
96 e => {
97 kerror!("tty error occurred while writing data to its input port, msg={e:?}");
98 return Err(SystemError::EBUSY);
99 }
100 }
101 }
102 }
103
104 impl DeviceINode for TtyDevice {
set_fs(&self, fs: alloc::sync::Weak<crate::filesystem::devfs::DevFS>)105 fn set_fs(&self, fs: alloc::sync::Weak<crate::filesystem::devfs::DevFS>) {
106 *self.fs.write() = fs;
107 }
108 }
109
110 impl IndexNode for TtyDevice {
111 /// @brief 打开TTY设备
112 ///
113 /// @param data 文件私有信息
114 /// @param mode 打开模式
115 ///
116 /// TTY设备通过mode来确定这个文件到底是stdin/stdout/stderr
117 /// - mode的值为O_RDONLY时,表示这个文件是stdin
118 /// - mode的值为O_WRONLY时,表示这个文件是stdout
119 /// - mode的值为O_WRONLY | O_SYNC时,表示这个文件是stderr
open(&self, data: &mut FilePrivateData, mode: &FileMode) -> Result<(), SystemError>120 fn open(&self, data: &mut FilePrivateData, mode: &FileMode) -> Result<(), SystemError> {
121 let mut p = TtyFilePrivateData::default();
122
123 // 检查打开模式
124 let accmode = mode.accmode();
125 if accmode == FileMode::O_RDONLY.accmode() {
126 p.flags.insert(TtyFileFlag::STDIN);
127 } else if accmode == FileMode::O_WRONLY.accmode() {
128 if mode.contains(FileMode::O_SYNC) {
129 p.flags.insert(TtyFileFlag::STDERR);
130 } else {
131 p.flags.insert(TtyFileFlag::STDOUT);
132 }
133 } else {
134 return Err(SystemError::EINVAL);
135 }
136
137 // 保存文件私有信息
138 *data = FilePrivateData::Tty(p);
139 return Ok(());
140 }
141
read_at( &self, _offset: usize, len: usize, buf: &mut [u8], data: &mut crate::filesystem::vfs::FilePrivateData, ) -> Result<usize, SystemError>142 fn read_at(
143 &self,
144 _offset: usize,
145 len: usize,
146 buf: &mut [u8],
147 data: &mut crate::filesystem::vfs::FilePrivateData,
148 ) -> Result<usize, SystemError> {
149 let _data: &mut TtyFilePrivateData = match self.verify_file_private_data(data) {
150 Ok(t) => t,
151 Err(e) => {
152 kerror!("Try to read tty device, but file private data type mismatch!");
153 return Err(e);
154 }
155 };
156 self.check_rw_param(len, buf)?;
157
158 // 读取stdin队列
159 let r: Result<usize, TtyError> = self.core.read_stdin(&mut buf[0..len], true);
160 if r.is_ok() {
161 return Ok(r.unwrap());
162 }
163
164 match r.unwrap_err() {
165 TtyError::EOF(n) => {
166 return Ok(n);
167 }
168
169 x => {
170 kerror!("Error occurred when reading tty, msg={x:?}");
171 return Err(SystemError::ECONNABORTED);
172 }
173 }
174 }
175
write_at( &self, _offset: usize, len: usize, buf: &[u8], data: &mut crate::filesystem::vfs::FilePrivateData, ) -> Result<usize, SystemError>176 fn write_at(
177 &self,
178 _offset: usize,
179 len: usize,
180 buf: &[u8],
181 data: &mut crate::filesystem::vfs::FilePrivateData,
182 ) -> Result<usize, SystemError> {
183 let data: &mut TtyFilePrivateData = match self.verify_file_private_data(data) {
184 Ok(t) => t,
185 Err(e) => {
186 kerror!("Try to write tty device, but file private data type mismatch!");
187 return Err(e);
188 }
189 };
190
191 self.check_rw_param(len, buf)?;
192
193 // 根据当前文件是stdout还是stderr,选择不同的发送方式
194 let r: Result<usize, TtyError> = if data.flags.contains(TtyFileFlag::STDOUT) {
195 self.core.stdout(&buf[0..len], true)
196 } else if data.flags.contains(TtyFileFlag::STDERR) {
197 self.core.stderr(&buf[0..len], true)
198 } else {
199 return Err(SystemError::EPERM);
200 };
201
202 if r.is_ok() {
203 self.sync().expect("Failed to sync tty device!");
204 return Ok(r.unwrap());
205 }
206
207 let r: TtyError = r.unwrap_err();
208 kerror!("Error occurred when writing tty deivce. Error msg={r:?}");
209 return Err(SystemError::EIO);
210 }
211
poll(&self) -> Result<crate::filesystem::vfs::PollStatus, SystemError>212 fn poll(&self) -> Result<crate::filesystem::vfs::PollStatus, SystemError> {
213 return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
214 }
215
fs(&self) -> Arc<dyn crate::filesystem::vfs::FileSystem>216 fn fs(&self) -> Arc<dyn crate::filesystem::vfs::FileSystem> {
217 return self.fs.read().upgrade().unwrap();
218 }
219
as_any_ref(&self) -> &dyn core::any::Any220 fn as_any_ref(&self) -> &dyn core::any::Any {
221 self
222 }
223
list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, SystemError>224 fn list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, SystemError> {
225 return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
226 }
227
metadata(&self) -> Result<Metadata, SystemError>228 fn metadata(&self) -> Result<Metadata, SystemError> {
229 return Ok(self.private_data.read().metadata.clone());
230 }
231
close(&self, _data: &mut FilePrivateData) -> Result<(), SystemError>232 fn close(&self, _data: &mut FilePrivateData) -> Result<(), SystemError> {
233 return Ok(());
234 }
235
sync(&self) -> Result<(), SystemError>236 fn sync(&self) -> Result<(), SystemError> {
237 // TODO: 引入IO重定向后,需要将输出重定向到对应的设备。
238 // 目前只是简单的输出到屏幕(为了实现的简便)
239
240 loop {
241 let mut buf = [0u8; 512];
242 let r: Result<usize, TtyError> = self.core.output(&mut buf[0..511], false);
243 let len;
244 match r {
245 Ok(x) => {
246 len = x;
247 }
248 Err(TtyError::EOF(x)) | Err(TtyError::BufferEmpty(x)) => {
249 len = x;
250 }
251 _ => return Err(SystemError::EIO),
252 }
253
254 if len == 0 {
255 break;
256 }
257 // 输出到屏幕
258 unsafe {
259 for x in buf {
260 textui_putchar(x as u16, WHITE, BLACK);
261 }
262 }
263 }
264 return Ok(());
265 }
266 }
267
268 impl TtyDevicePrivateData {
new(name: &str) -> RwLock<Self>269 pub fn new(name: &str) -> RwLock<Self> {
270 let mut metadata = Metadata::new(FileType::CharDevice, 0o755);
271 metadata.size = TtyCore::STDIN_BUF_SIZE as i64;
272 return RwLock::new(TtyDevicePrivateData {
273 name: name.to_string(),
274 metadata,
275 });
276 }
277 }
278
279 /// @brief 导出到C的tty初始化函数
280 #[no_mangle]
rs_tty_init() -> i32281 pub extern "C" fn rs_tty_init() -> i32 {
282 let r = tty_init();
283 if r.is_ok() {
284 return 0;
285 } else {
286 return r.unwrap_err().to_posix_errno();
287 }
288 }
289
290 /// @brief 初始化TTY设备
tty_init() -> Result<(), SystemError>291 pub fn tty_init() -> Result<(), SystemError> {
292 let tty: Arc<TtyDevice> = TtyDevice::new("tty0");
293 let devfs_root_inode = ROOT_INODE().lookup("/dev");
294 if devfs_root_inode.is_err() {
295 return Err(devfs_root_inode.unwrap_err());
296 }
297 // 当前关闭键盘输入回显
298 // TODO: 完善Termios之后, 改为默认开启键盘输入回显.
299 tty.core.disable_echo();
300 let guard = TTY_DEVICES.upgradeable_read();
301
302 // 如果已经存在了这个设备
303 if guard.contains_key("tty0") {
304 return Err(SystemError::EEXIST);
305 }
306
307 let mut guard = guard.upgrade();
308
309 guard.insert("tty0".to_string(), tty.clone());
310
311 drop(guard);
312
313 let r = devfs_register(&tty.name(), tty);
314 if r.is_err() {
315 return Err(devfs_root_inode.unwrap_err());
316 }
317
318 return Ok(());
319 }
320