//! Implement INode for Stdin & Stdout use alloc::{collections::vec_deque::VecDeque, string::String, sync::Arc}; use core::any::Any; use rcore_fs::vfs::*; use crate::sync::Condvar; use crate::sync::SpinNoIrqLock as Mutex; #[derive(Default)] pub struct Stdin { buf: Mutex>, pub pushed: Condvar, } impl Stdin { pub fn push(&self, c: char) { self.buf.lock().push_back(c); self.pushed.notify_one(); } pub fn pop(&self) -> char { loop { let ret = self.buf.lock().pop_front(); match ret { Some(c) => return c, None => self.pushed._wait(), } } } pub fn can_read(&self) -> bool { self.buf.lock().len() > 0 } } #[derive(Default)] pub struct Stdout; lazy_static! { pub static ref STDIN: Arc = Arc::new(Stdin::default()); pub static ref STDOUT: Arc = Arc::new(Stdout::default()); } // 32bits total, command in lower 16bits, size of the parameter structure in the lower 14 bits of the upper 16 bits // higher 2 bits: 01 = write, 10 = read #[cfg(not(target_arch = "mips"))] const TCGETS: u32 = 0x5401; #[cfg(target_arch = "mips")] const TCGETS: u32 = 0x540D; #[cfg(not(target_arch = "mips"))] const TIOCGPGRP: u32 = 0x540F; // _IOR('t', 119, int) #[cfg(target_arch = "mips")] const TIOCGPGRP: u32 = 0x4_004_74_77; #[cfg(not(target_arch = "mips"))] const TIOCSPGRP: u32 = 0x5410; // _IOW('t', 118, int) #[cfg(target_arch = "mips")] const TIOCSPGRP: u32 = 0x8_004_74_76; #[cfg(not(target_arch = "mips"))] const TIOCGWINSZ: u32 = 0x5413; // _IOR('t', 104, struct winsize) #[cfg(target_arch = "mips")] const TIOCGWINSZ: u32 = 0x4_008_74_68; // TODO: better way to provide default impl? macro_rules! impl_inode { () => { fn metadata(&self) -> Result { Err(FsError::NotSupported) } fn set_metadata(&self, _metadata: &Metadata) -> Result<()> { Ok(()) } fn sync_all(&self) -> Result<()> { Ok(()) } fn sync_data(&self) -> Result<()> { Ok(()) } fn resize(&self, _len: usize) -> Result<()> { Err(FsError::NotSupported) } fn create(&self, _name: &str, _type_: FileType, _mode: u32) -> Result> { Err(FsError::NotDir) } fn unlink(&self, _name: &str) -> Result<()> { Err(FsError::NotDir) } fn link(&self, _name: &str, _other: &Arc) -> Result<()> { Err(FsError::NotDir) } fn move_(&self, _old_name: &str, _target: &Arc, _new_name: &str) -> Result<()> { Err(FsError::NotDir) } fn find(&self, _name: &str) -> Result> { Err(FsError::NotDir) } fn get_entry(&self, _id: usize) -> Result { Err(FsError::NotDir) } fn io_control(&self, cmd: u32, data: usize) -> Result<()> { match cmd { TCGETS | TIOCGWINSZ | TIOCSPGRP => { // pretend to be tty Ok(()) }, TIOCGPGRP => { // pretend to be have a tty process group // TODO: verify pointer unsafe { *(data as *mut u32) = 0 }; Ok(()) } _ => Err(FsError::NotSupported) } } fn fs(&self) -> Arc { unimplemented!() } fn as_any_ref(&self) -> &Any { self } }; } impl INode for Stdin { fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result { buf[0] = self.pop() as u8; Ok(1) } fn write_at(&self, _offset: usize, _buf: &[u8]) -> Result { unimplemented!() } fn poll(&self) -> Result { Ok(PollStatus { read: self.can_read(), write: false, error: false, }) } impl_inode!(); } impl INode for Stdout { fn read_at(&self, _offset: usize, _buf: &mut [u8]) -> Result { unimplemented!() } fn write_at(&self, _offset: usize, buf: &[u8]) -> Result { use core::str; //we do not care the utf-8 things, we just want to print it! let s = unsafe { str::from_utf8_unchecked(buf) }; print!("{}", s); Ok(buf.len()) } fn poll(&self) -> Result { Ok(PollStatus { read: false, write: true, error: false, }) } impl_inode!(); }