120e3152eSlogin use alloc::{ 220e3152eSlogin collections::BTreeMap, 320e3152eSlogin string::{String, ToString}, 420e3152eSlogin sync::{Arc, Weak}, 520e3152eSlogin }; 691e9d4abSLoGin use system_error::SystemError; 7*c566df45SLoGin use unified_init::macros::unified_init; 80d48c3c9Slogin 90d48c3c9Slogin use crate::{ 100d48c3c9Slogin filesystem::{ 1120e3152eSlogin devfs::{devfs_register, DevFS, DeviceINode}, 126b4e7a29SLoGin vfs::{ 136b4e7a29SLoGin file::FileMode, syscall::ModeType, FilePrivateData, FileType, IndexNode, Metadata, 146b4e7a29SLoGin ROOT_INODE, 156b4e7a29SLoGin }, 160d48c3c9Slogin }, 17*c566df45SLoGin init::initcall::INITCALL_DEVICE, 18d7b31a96SGou Ngai kerror, 19abe3a6eaShanjiezhou libs::{ 20abe3a6eaShanjiezhou lib_ui::textui::{textui_putchar, FontColor}, 21abe3a6eaShanjiezhou rwlock::RwLock, 22abe3a6eaShanjiezhou }, 230d48c3c9Slogin }; 240d48c3c9Slogin 25a03c4f9dSLoGin use super::{serial::serial_init, TtyCore, TtyError, TtyFileFlag, TtyFilePrivateData}; 260d48c3c9Slogin 2720e3152eSlogin lazy_static! { 2820e3152eSlogin /// 所有TTY设备的B树。用于根据名字,找到Arc<TtyDevice> 2920e3152eSlogin /// TODO: 待设备驱动模型完善,具有类似功能的机制后,删掉这里 3020e3152eSlogin pub static ref TTY_DEVICES: RwLock<BTreeMap<String, Arc<TtyDevice>>> = RwLock::new(BTreeMap::new()); 3120e3152eSlogin } 3220e3152eSlogin 3320e3152eSlogin /// @brief TTY设备 340d48c3c9Slogin #[derive(Debug)] 350d48c3c9Slogin pub struct TtyDevice { 3620e3152eSlogin /// TTY核心 370d48c3c9Slogin core: TtyCore, 3820e3152eSlogin /// TTY所属的文件系统 3920e3152eSlogin fs: RwLock<Weak<DevFS>>, 4020e3152eSlogin /// TTY设备私有信息 4120e3152eSlogin private_data: RwLock<TtyDevicePrivateData>, 4220e3152eSlogin } 430d48c3c9Slogin 4420e3152eSlogin #[derive(Debug)] 4520e3152eSlogin struct TtyDevicePrivateData { 4620e3152eSlogin /// TTY设备名(如tty1) 4720e3152eSlogin name: String, 4820e3152eSlogin /// TTY设备文件的元数据 4920e3152eSlogin metadata: Metadata, 5020e3152eSlogin // TODO: 增加指向输出端口连接的设备的指针 510d48c3c9Slogin } 520d48c3c9Slogin 530d48c3c9Slogin impl TtyDevice { 5420e3152eSlogin pub fn new(name: &str) -> Arc<TtyDevice> { 5520e3152eSlogin let result = Arc::new(TtyDevice { 560d48c3c9Slogin core: TtyCore::new(), 570d48c3c9Slogin fs: RwLock::new(Weak::default()), 5820e3152eSlogin private_data: TtyDevicePrivateData::new(name), 590d48c3c9Slogin }); 6020e3152eSlogin // 默认开启输入回显 6120e3152eSlogin result.core.enable_echo(); 6220e3152eSlogin return result; 630d48c3c9Slogin } 640d48c3c9Slogin 6520e3152eSlogin /// @brief 判断文件私有信息是否为TTY文件的私有信息 660d48c3c9Slogin #[inline] 670d48c3c9Slogin fn verify_file_private_data<'a>( 680d48c3c9Slogin &self, 690d48c3c9Slogin private_data: &'a mut FilePrivateData, 70676b8ef6SMork ) -> Result<&'a mut TtyFilePrivateData, SystemError> { 710d48c3c9Slogin if let FilePrivateData::Tty(t) = private_data { 720d48c3c9Slogin return Ok(t); 730d48c3c9Slogin } 74676b8ef6SMork return Err(SystemError::EIO); 750d48c3c9Slogin } 7620e3152eSlogin 7720e3152eSlogin /// @brief 获取TTY设备名 7820e3152eSlogin #[inline] 7920e3152eSlogin pub fn name(&self) -> String { 8020e3152eSlogin return self.private_data.read().name.clone(); 8120e3152eSlogin } 8220e3152eSlogin 8320e3152eSlogin /// @brief 检查TTY文件的读写参数是否合法 8420e3152eSlogin #[inline] 8520e3152eSlogin pub fn check_rw_param(&self, len: usize, buf: &[u8]) -> Result<(), SystemError> { 8620e3152eSlogin if len > buf.len() { 8720e3152eSlogin return Err(SystemError::EINVAL); 8820e3152eSlogin } 8920e3152eSlogin return Ok(()); 9020e3152eSlogin } 9120e3152eSlogin 9220e3152eSlogin /// @brief 向TTY的输入端口导入数据 9320e3152eSlogin pub fn input(&self, buf: &[u8]) -> Result<usize, SystemError> { 9420e3152eSlogin let r: Result<usize, TtyError> = self.core.input(buf, false); 9520e3152eSlogin if r.is_ok() { 9620e3152eSlogin return Ok(r.unwrap()); 9720e3152eSlogin } 9820e3152eSlogin 9920e3152eSlogin let r = r.unwrap_err(); 10020e3152eSlogin match r { 10120e3152eSlogin TtyError::BufferFull(x) => return Ok(x), 10220e3152eSlogin TtyError::Closed => return Err(SystemError::ENODEV), 10320e3152eSlogin e => { 10420e3152eSlogin kerror!("tty error occurred while writing data to its input port, msg={e:?}"); 10520e3152eSlogin return Err(SystemError::EBUSY); 10620e3152eSlogin } 10720e3152eSlogin } 10820e3152eSlogin } 1090d48c3c9Slogin } 1100d48c3c9Slogin 1110d48c3c9Slogin impl DeviceINode for TtyDevice { 1120d48c3c9Slogin fn set_fs(&self, fs: alloc::sync::Weak<crate::filesystem::devfs::DevFS>) { 1130d48c3c9Slogin *self.fs.write() = fs; 1140d48c3c9Slogin } 1150d48c3c9Slogin } 1160d48c3c9Slogin 1170d48c3c9Slogin impl IndexNode for TtyDevice { 11820e3152eSlogin /// @brief 打开TTY设备 11920e3152eSlogin /// 12020e3152eSlogin /// @param data 文件私有信息 12120e3152eSlogin /// @param mode 打开模式 12220e3152eSlogin /// 12320e3152eSlogin /// TTY设备通过mode来确定这个文件到底是stdin/stdout/stderr 12420e3152eSlogin /// - mode的值为O_RDONLY时,表示这个文件是stdin 12520e3152eSlogin /// - mode的值为O_WRONLY时,表示这个文件是stdout 12620e3152eSlogin /// - mode的值为O_WRONLY | O_SYNC时,表示这个文件是stderr 127676b8ef6SMork fn open(&self, data: &mut FilePrivateData, mode: &FileMode) -> Result<(), SystemError> { 12820e3152eSlogin let mut p = TtyFilePrivateData::default(); 12920e3152eSlogin 13020e3152eSlogin // 检查打开模式 13120e3152eSlogin let accmode = mode.accmode(); 13220e3152eSlogin if accmode == FileMode::O_RDONLY.accmode() { 13320e3152eSlogin p.flags.insert(TtyFileFlag::STDIN); 13420e3152eSlogin } else if accmode == FileMode::O_WRONLY.accmode() { 13520e3152eSlogin if mode.contains(FileMode::O_SYNC) { 13620e3152eSlogin p.flags.insert(TtyFileFlag::STDERR); 13720e3152eSlogin } else { 13820e3152eSlogin p.flags.insert(TtyFileFlag::STDOUT); 13920e3152eSlogin } 14020e3152eSlogin } else { 14120e3152eSlogin return Err(SystemError::EINVAL); 14220e3152eSlogin } 14320e3152eSlogin 14420e3152eSlogin // 保存文件私有信息 1450d48c3c9Slogin *data = FilePrivateData::Tty(p); 1460d48c3c9Slogin return Ok(()); 1470d48c3c9Slogin } 1480d48c3c9Slogin 1490d48c3c9Slogin fn read_at( 1500d48c3c9Slogin &self, 15120e3152eSlogin _offset: usize, 1520d48c3c9Slogin len: usize, 1530d48c3c9Slogin buf: &mut [u8], 1540d48c3c9Slogin data: &mut crate::filesystem::vfs::FilePrivateData, 155676b8ef6SMork ) -> Result<usize, SystemError> { 1560d48c3c9Slogin let _data: &mut TtyFilePrivateData = match self.verify_file_private_data(data) { 1570d48c3c9Slogin Ok(t) => t, 1580d48c3c9Slogin Err(e) => { 1590d48c3c9Slogin kerror!("Try to read tty device, but file private data type mismatch!"); 1600d48c3c9Slogin return Err(e); 1610d48c3c9Slogin } 1620d48c3c9Slogin }; 16320e3152eSlogin self.check_rw_param(len, buf)?; 1640d48c3c9Slogin 1650d48c3c9Slogin // 读取stdin队列 16620e3152eSlogin let r: Result<usize, TtyError> = self.core.read_stdin(&mut buf[0..len], true); 1670d48c3c9Slogin if r.is_ok() { 1680d48c3c9Slogin return Ok(r.unwrap()); 1690d48c3c9Slogin } 1700d48c3c9Slogin 1710d48c3c9Slogin match r.unwrap_err() { 1720d48c3c9Slogin TtyError::EOF(n) => { 1730d48c3c9Slogin return Ok(n); 1740d48c3c9Slogin } 17520e3152eSlogin 1760d48c3c9Slogin x => { 1770d48c3c9Slogin kerror!("Error occurred when reading tty, msg={x:?}"); 178676b8ef6SMork return Err(SystemError::ECONNABORTED); 1790d48c3c9Slogin } 1800d48c3c9Slogin } 1810d48c3c9Slogin } 1820d48c3c9Slogin 1830d48c3c9Slogin fn write_at( 1840d48c3c9Slogin &self, 18520e3152eSlogin _offset: usize, 1860d48c3c9Slogin len: usize, 1870d48c3c9Slogin buf: &[u8], 1880d48c3c9Slogin data: &mut crate::filesystem::vfs::FilePrivateData, 189676b8ef6SMork ) -> Result<usize, SystemError> { 1900d48c3c9Slogin let data: &mut TtyFilePrivateData = match self.verify_file_private_data(data) { 1910d48c3c9Slogin Ok(t) => t, 1920d48c3c9Slogin Err(e) => { 1930d48c3c9Slogin kerror!("Try to write tty device, but file private data type mismatch!"); 1940d48c3c9Slogin return Err(e); 1950d48c3c9Slogin } 1960d48c3c9Slogin }; 1970d48c3c9Slogin 19820e3152eSlogin self.check_rw_param(len, buf)?; 19920e3152eSlogin 2000d48c3c9Slogin // 根据当前文件是stdout还是stderr,选择不同的发送方式 2010d48c3c9Slogin let r: Result<usize, TtyError> = if data.flags.contains(TtyFileFlag::STDOUT) { 20220e3152eSlogin self.core.stdout(&buf[0..len], true) 2030d48c3c9Slogin } else if data.flags.contains(TtyFileFlag::STDERR) { 20420e3152eSlogin self.core.stderr(&buf[0..len], true) 2050d48c3c9Slogin } else { 206676b8ef6SMork return Err(SystemError::EPERM); 2070d48c3c9Slogin }; 2080d48c3c9Slogin 2090d48c3c9Slogin if r.is_ok() { 21020e3152eSlogin self.sync().expect("Failed to sync tty device!"); 2110d48c3c9Slogin return Ok(r.unwrap()); 2120d48c3c9Slogin } 2130d48c3c9Slogin 2140d48c3c9Slogin let r: TtyError = r.unwrap_err(); 2150d48c3c9Slogin kerror!("Error occurred when writing tty deivce. Error msg={r:?}"); 216676b8ef6SMork return Err(SystemError::EIO); 2170d48c3c9Slogin } 2180d48c3c9Slogin 2190d48c3c9Slogin fn fs(&self) -> Arc<dyn crate::filesystem::vfs::FileSystem> { 2200d48c3c9Slogin return self.fs.read().upgrade().unwrap(); 2210d48c3c9Slogin } 2220d48c3c9Slogin 2230d48c3c9Slogin fn as_any_ref(&self) -> &dyn core::any::Any { 2240d48c3c9Slogin self 2250d48c3c9Slogin } 2260d48c3c9Slogin 227676b8ef6SMork fn list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, SystemError> { 22879a452ceShoumkh return Err(SystemError::EOPNOTSUPP_OR_ENOTSUP); 2290d48c3c9Slogin } 23020e3152eSlogin 23120e3152eSlogin fn metadata(&self) -> Result<Metadata, SystemError> { 23220e3152eSlogin return Ok(self.private_data.read().metadata.clone()); 23320e3152eSlogin } 23420e3152eSlogin 23520e3152eSlogin fn close(&self, _data: &mut FilePrivateData) -> Result<(), SystemError> { 23620e3152eSlogin return Ok(()); 23720e3152eSlogin } 23820e3152eSlogin 23920e3152eSlogin fn sync(&self) -> Result<(), SystemError> { 24020e3152eSlogin // TODO: 引入IO重定向后,需要将输出重定向到对应的设备。 24120e3152eSlogin // 目前只是简单的输出到屏幕(为了实现的简便) 24220e3152eSlogin 24320e3152eSlogin loop { 24420e3152eSlogin let mut buf = [0u8; 512]; 245d7b31a96SGou Ngai let r: Result<usize, TtyError> = self.core.output(&mut buf[0..511], false); 24620e3152eSlogin let len; 24720e3152eSlogin match r { 24820e3152eSlogin Ok(x) => { 24920e3152eSlogin len = x; 25020e3152eSlogin } 25120e3152eSlogin Err(TtyError::EOF(x)) | Err(TtyError::BufferEmpty(x)) => { 25220e3152eSlogin len = x; 25320e3152eSlogin } 25420e3152eSlogin _ => return Err(SystemError::EIO), 25520e3152eSlogin } 25620e3152eSlogin 25720e3152eSlogin if len == 0 { 25820e3152eSlogin break; 25920e3152eSlogin } 26020e3152eSlogin // 输出到屏幕 261abe3a6eaShanjiezhou 26211110997Shanjiezhou for x in 0..len { 26311110997Shanjiezhou textui_putchar(buf[x] as char, FontColor::WHITE, FontColor::BLACK).ok(); 264d7b31a96SGou Ngai } 26520e3152eSlogin } 26620e3152eSlogin return Ok(()); 26720e3152eSlogin } 26811110997Shanjiezhou fn resize(&self, _len: usize) -> Result<(), SystemError> { 26911110997Shanjiezhou return Ok(()); 27011110997Shanjiezhou } 27120e3152eSlogin } 27220e3152eSlogin 27320e3152eSlogin impl TtyDevicePrivateData { 27420e3152eSlogin pub fn new(name: &str) -> RwLock<Self> { 2756b4e7a29SLoGin let mut metadata = Metadata::new(FileType::CharDevice, ModeType::from_bits_truncate(0o755)); 27620e3152eSlogin metadata.size = TtyCore::STDIN_BUF_SIZE as i64; 27720e3152eSlogin return RwLock::new(TtyDevicePrivateData { 27820e3152eSlogin name: name.to_string(), 27920e3152eSlogin metadata, 28020e3152eSlogin }); 28120e3152eSlogin } 28220e3152eSlogin } 28320e3152eSlogin 28420e3152eSlogin /// @brief 初始化TTY设备 285*c566df45SLoGin #[unified_init(INITCALL_DEVICE)] 28620e3152eSlogin pub fn tty_init() -> Result<(), SystemError> { 28720e3152eSlogin let tty: Arc<TtyDevice> = TtyDevice::new("tty0"); 28820e3152eSlogin let devfs_root_inode = ROOT_INODE().lookup("/dev"); 28920e3152eSlogin if devfs_root_inode.is_err() { 29020e3152eSlogin return Err(devfs_root_inode.unwrap_err()); 29120e3152eSlogin } 29220e3152eSlogin // 当前关闭键盘输入回显 29320e3152eSlogin // TODO: 完善Termios之后, 改为默认开启键盘输入回显. 29420e3152eSlogin tty.core.disable_echo(); 29520e3152eSlogin let guard = TTY_DEVICES.upgradeable_read(); 29620e3152eSlogin 29720e3152eSlogin // 如果已经存在了这个设备 29820e3152eSlogin if guard.contains_key("tty0") { 29920e3152eSlogin return Err(SystemError::EEXIST); 30020e3152eSlogin } 30120e3152eSlogin 30220e3152eSlogin let mut guard = guard.upgrade(); 30320e3152eSlogin 30420e3152eSlogin guard.insert("tty0".to_string(), tty.clone()); 30520e3152eSlogin 30620e3152eSlogin drop(guard); 30720e3152eSlogin 30820e3152eSlogin let r = devfs_register(&tty.name(), tty); 30920e3152eSlogin if r.is_err() { 31020e3152eSlogin return Err(devfs_root_inode.unwrap_err()); 31120e3152eSlogin } 31220e3152eSlogin 313a03c4f9dSLoGin serial_init()?; 31420e3152eSlogin return Ok(()); 3150d48c3c9Slogin } 316