xref: /DragonOS/kernel/src/driver/tty/tty_device.rs (revision f110d330d5493f383067b4e82ebbfb72f40457b2)
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::{serial::serial_init, 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 fs(&self) -> Arc<dyn crate::filesystem::vfs::FileSystem> {
218         return self.fs.read().upgrade().unwrap();
219     }
220 
221     fn as_any_ref(&self) -> &dyn core::any::Any {
222         self
223     }
224 
225     fn list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, SystemError> {
226         return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP);
227     }
228 
229     fn metadata(&self) -> Result<Metadata, SystemError> {
230         return Ok(self.private_data.read().metadata.clone());
231     }
232 
233     fn close(&self, _data: &mut FilePrivateData) -> Result<(), SystemError> {
234         return Ok(());
235     }
236 
237     fn sync(&self) -> Result<(), SystemError> {
238         // TODO: 引入IO重定向后,需要将输出重定向到对应的设备。
239         // 目前只是简单的输出到屏幕(为了实现的简便)
240 
241         loop {
242             let mut buf = [0u8; 512];
243             let r: Result<usize, TtyError> = self.core.output(&mut buf[0..511], false);
244             let len;
245             match r {
246                 Ok(x) => {
247                     len = x;
248                 }
249                 Err(TtyError::EOF(x)) | Err(TtyError::BufferEmpty(x)) => {
250                     len = x;
251                 }
252                 _ => return Err(SystemError::EIO),
253             }
254 
255             if len == 0 {
256                 break;
257             }
258             // 输出到屏幕
259 
260             for x in 0..len {
261                 textui_putchar(buf[x] as char, FontColor::WHITE, FontColor::BLACK).ok();
262             }
263         }
264         return Ok(());
265     }
266     fn resize(&self, _len: usize) -> Result<(), SystemError> {
267         return Ok(());
268     }
269 }
270 
271 impl TtyDevicePrivateData {
272     pub fn new(name: &str) -> RwLock<Self> {
273         let mut metadata = Metadata::new(FileType::CharDevice, ModeType::from_bits_truncate(0o755));
274         metadata.size = TtyCore::STDIN_BUF_SIZE as i64;
275         return RwLock::new(TtyDevicePrivateData {
276             name: name.to_string(),
277             metadata,
278         });
279     }
280 }
281 
282 /// @brief 初始化TTY设备
283 pub fn tty_init() -> Result<(), SystemError> {
284     let tty: Arc<TtyDevice> = TtyDevice::new("tty0");
285     let devfs_root_inode = ROOT_INODE().lookup("/dev");
286     if devfs_root_inode.is_err() {
287         return Err(devfs_root_inode.unwrap_err());
288     }
289     // 当前关闭键盘输入回显
290     // TODO: 完善Termios之后, 改为默认开启键盘输入回显.
291     tty.core.disable_echo();
292     let guard = TTY_DEVICES.upgradeable_read();
293 
294     // 如果已经存在了这个设备
295     if guard.contains_key("tty0") {
296         return Err(SystemError::EEXIST);
297     }
298 
299     let mut guard = guard.upgrade();
300 
301     guard.insert("tty0".to_string(), tty.clone());
302 
303     drop(guard);
304 
305     let r = devfs_register(&tty.name(), tty);
306     if r.is_err() {
307         return Err(devfs_root_inode.unwrap_err());
308     }
309 
310     serial_init()?;
311     return Ok(());
312 }
313