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