1 use core::sync::atomic::Ordering; 2 3 use alloc::{ 4 string::{String, ToString}, 5 sync::Arc, 6 vec::Vec, 7 }; 8 use system_error::SystemError; 9 10 use crate::{ 11 driver::{ 12 base::device::{ 13 device_number::{DeviceNumber, Major}, 14 device_register, IdTable, 15 }, 16 video::fbdev::base::fbcon::framebuffer_console::BlittingFbConsole, 17 }, 18 filesystem::devfs::devfs_register, 19 libs::spinlock::SpinLock, 20 }; 21 22 use self::virtual_console::{VirtualConsoleData, CURRENT_VCNUM}; 23 24 use super::{ 25 console::ConsoleSwitch, 26 termios::{InputMode, TTY_STD_TERMIOS}, 27 tty_core::{TtyCore, TtyCoreData}, 28 tty_device::{TtyDevice, TtyType}, 29 tty_driver::{TtyDriver, TtyDriverManager, TtyDriverType, TtyOperation}, 30 }; 31 32 pub mod console_map; 33 pub mod virtual_console; 34 35 pub const MAX_NR_CONSOLES: u32 = 63; 36 pub const VC_MAXCOL: usize = 32767; 37 pub const VC_MAXROW: usize = 32767; 38 39 pub const DEFAULT_RED: [u16; 16] = [ 40 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0xaa, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 0x55, 0xff, 41 ]; 42 43 pub const DEFAULT_GREEN: [u16; 16] = [ 44 0x00, 0x00, 0xaa, 0x55, 0x00, 0x00, 0xaa, 0xaa, 0x55, 0x55, 0xff, 0xff, 0x55, 0x55, 0xff, 0xff, 45 ]; 46 47 pub const DEFAULT_BLUE: [u16; 16] = [ 48 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 49 ]; 50 51 pub const COLOR_TABLE: &[u8] = &[0, 4, 2, 6, 1, 5, 3, 7, 8, 12, 10, 14, 9, 13, 11, 15]; 52 53 lazy_static! { 54 pub static ref VIRT_CONSOLES: Vec<Arc<SpinLock<VirtualConsoleData>>> = { 55 let mut v = Vec::with_capacity(MAX_NR_CONSOLES as usize); 56 for i in 0..MAX_NR_CONSOLES as usize { 57 v.push(Arc::new(SpinLock::new(VirtualConsoleData::new(i)))); 58 } 59 60 v 61 }; 62 } 63 64 #[derive(Debug, Clone, Copy, Default)] 65 pub struct Color { 66 pub red: u16, 67 pub green: u16, 68 pub blue: u16, 69 pub transp: u16, 70 } 71 72 impl Color { 73 pub fn from_256(col: u32) -> Self { 74 let mut color = Self::default(); 75 if col < 8 { 76 color.red = if col & 1 != 0 { 0xaa } else { 0x00 }; 77 color.green = if col & 2 != 0 { 0xaa } else { 0x00 }; 78 color.blue = if col & 4 != 0 { 0xaa } else { 0x00 }; 79 } else if col < 16 { 80 color.red = if col & 1 != 0 { 0xff } else { 0x55 }; 81 color.green = if col & 2 != 0 { 0xff } else { 0x55 }; 82 color.blue = if col & 4 != 0 { 0xff } else { 0x55 }; 83 } else if col < 232 { 84 color.red = ((col - 16) / 36 * 85 / 2) as u16; 85 color.green = ((col - 16) / 6 % 6 * 85 / 2) as u16; 86 color.blue = ((col - 16) % 6 * 85 / 2) as u16; 87 } else { 88 let col = (col * 10 - 2312) as u16; 89 color.red = col; 90 color.green = col; 91 color.blue = col; 92 } 93 94 color 95 } 96 } 97 98 #[derive(Debug)] 99 pub struct TtyConsoleDriverInner { 100 console: Arc<BlittingFbConsole>, 101 } 102 103 impl TtyConsoleDriverInner { 104 pub fn new() -> Result<Self, SystemError> { 105 Ok(Self { 106 console: Arc::new(BlittingFbConsole::new()?), 107 }) 108 } 109 110 fn do_write(&self, tty: &TtyCoreData, buf: &[u8], mut nr: usize) -> Result<usize, SystemError> { 111 // 关闭中断 112 let mut vc_data = tty.vc_data_irqsave(); 113 114 let mut offset = 0; 115 116 // 这个参数是用来扫描unicode字符的,但是这部分目前未完成,先写着 117 let mut rescan = false; 118 let mut ch: u32 = 0; 119 120 let mut draw = DrawRegion::default(); 121 122 // 首先隐藏光标再写 123 vc_data.hide_cursor(); 124 125 while nr != 0 { 126 if !rescan { 127 ch = buf[offset] as u32; 128 offset += 1; 129 nr -= 1; 130 } 131 132 let (tc, rescan_last) = vc_data.translate(&mut ch); 133 if tc.is_none() { 134 // 表示未转换完成 135 continue; 136 } 137 138 let tc = tc.unwrap(); 139 rescan = rescan_last; 140 141 if vc_data.is_control(tc, ch) { 142 vc_data.flush(&mut draw); 143 vc_data.do_control(ch); 144 continue; 145 } 146 147 if !vc_data.console_write_normal(tc, ch, &mut draw) { 148 continue; 149 } 150 } 151 152 vc_data.flush(&mut draw); 153 154 // TODO: notify update 155 return Ok(offset); 156 } 157 } 158 159 impl TtyOperation for TtyConsoleDriverInner { 160 fn install(&self, _driver: Arc<TtyDriver>, tty: Arc<TtyCore>) -> Result<(), SystemError> { 161 let tty_core = tty.core(); 162 let mut vc_data = VIRT_CONSOLES[tty_core.index()].lock(); 163 164 self.console.con_init(&mut vc_data, true)?; 165 if vc_data.complement_mask == 0 { 166 vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 }; 167 } 168 vc_data.s_complement_mask = vc_data.complement_mask; 169 // vc_data.bytes_per_row = vc_data.cols << 1; 170 vc_data.index = tty_core.index(); 171 vc_data.bottom = vc_data.rows; 172 vc_data.set_driver_funcs(Arc::downgrade( 173 &(self.console.clone() as Arc<dyn ConsoleSwitch>), 174 )); 175 176 // todo: unicode字符集处理? 177 178 if vc_data.cols > VC_MAXCOL || vc_data.rows > VC_MAXROW { 179 return Err(SystemError::EINVAL); 180 } 181 182 vc_data.init(None, None, true); 183 vc_data.update_attr(); 184 185 let window_size = tty_core.window_size_upgradeable(); 186 if window_size.col == 0 && window_size.row == 0 { 187 let mut window_size = window_size.upgrade(); 188 window_size.col = vc_data.cols as u16; 189 window_size.row = vc_data.rows as u16; 190 } 191 192 if vc_data.utf { 193 tty_core.termios_write().input_mode.insert(InputMode::IUTF8); 194 } else { 195 tty_core.termios_write().input_mode.remove(InputMode::IUTF8); 196 } 197 198 // 设置tty的端口为vc端口 199 vc_data.port().setup_internal_tty(Arc::downgrade(&tty)); 200 tty.set_port(vc_data.port()); 201 // 加入sysfs? 202 203 CURRENT_VCNUM.store(tty_core.index() as isize, Ordering::SeqCst); 204 Ok(()) 205 } 206 207 fn open(&self, _tty: &TtyCoreData) -> Result<(), SystemError> { 208 Ok(()) 209 } 210 211 fn write_room(&self, _tty: &TtyCoreData) -> usize { 212 32768 213 } 214 215 /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/tty/vt/vt.c#2894 216 #[inline(never)] 217 fn write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result<usize, SystemError> { 218 // if String::from_utf8_lossy(buf) == "Hello world!\n" { 219 // loop {} 220 // } 221 let ret = self.do_write(tty, buf, nr); 222 self.flush_chars(tty); 223 ret 224 } 225 226 #[inline(never)] 227 fn flush_chars(&self, tty: &TtyCoreData) { 228 let mut vc_data = tty.vc_data_irqsave(); 229 vc_data.set_cursor(); 230 } 231 232 fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> { 233 self.write(tty, &[ch], 1)?; 234 Ok(()) 235 } 236 237 fn ioctl(&self, _tty: Arc<TtyCore>, _cmd: u32, _arg: usize) -> Result<(), SystemError> { 238 // TODO 239 Err(SystemError::ENOIOCTLCMD) 240 } 241 242 fn close(&self, _tty: Arc<TtyCore>) -> Result<(), SystemError> { 243 Ok(()) 244 } 245 246 fn resize( 247 &self, 248 _tty: Arc<TtyCore>, 249 _winsize: super::termios::WindowSize, 250 ) -> Result<(), SystemError> { 251 todo!() 252 } 253 } 254 255 #[derive(Debug, Clone)] 256 pub struct VtModeData { 257 mode: VtMode, 258 /// 释放请求时触发的信号 259 relsig: u16, 260 /// 获取请求时触发的信号 261 acqsig: u16, 262 } 263 264 #[allow(dead_code)] 265 #[derive(Debug, Clone)] 266 pub enum VtMode { 267 /// 自动切换模式,即在请求输入时自动切换到终端 268 Auto, 269 /// 手动切换模式,需要通过 ioctl 请求切换到终端 270 Process, 271 /// 等待终端确认,即在切换到终端时等待终端的确认信号 272 Ackacq, 273 } 274 275 /// 用于给vc确定要写入的buf位置 276 #[derive(Debug, Default)] 277 pub struct DrawRegion { 278 /// 偏移量 279 pub offset: usize, 280 /// 写入数量 281 pub size: usize, 282 pub x: Option<u32>, 283 } 284 285 // 初始化虚拟终端 286 #[inline(never)] 287 pub fn vty_init() -> Result<(), SystemError> { 288 // 注册虚拟终端设备并将虚拟终端设备加入到文件系统 289 let vc0 = TtyDevice::new( 290 "vc0".to_string(), 291 IdTable::new( 292 String::from("vc0"), 293 Some(DeviceNumber::new(Major::TTY_MAJOR, 0)), 294 ), 295 TtyType::Tty, 296 ); 297 // 注册tty设备 298 // CharDevOps::cdev_add( 299 // vc0.clone() as Arc<dyn CharDevice>, 300 // IdTable::new( 301 // String::from("vc0"), 302 // Some(DeviceNumber::new(Major::TTY_MAJOR, 0)), 303 // ), 304 // 1, 305 // )?; 306 307 // CharDevOps::register_chardev_region(DeviceNumber::new(Major::TTY_MAJOR, 0), 1, "/dev/vc/0")?; 308 device_register(vc0.clone())?; 309 devfs_register("vc0", vc0)?; 310 311 // vcs_init? 312 313 let console_driver = TtyDriver::new( 314 MAX_NR_CONSOLES, 315 "tty", 316 1, 317 Major::TTY_MAJOR, 318 0, 319 TtyDriverType::Console, 320 *TTY_STD_TERMIOS, 321 Arc::new(TtyConsoleDriverInner::new()?), 322 ); 323 324 TtyDriverManager::tty_register_driver(console_driver)?; 325 326 CURRENT_VCNUM.store(0, Ordering::SeqCst); 327 328 // 初始化键盘? 329 330 // TODO: 为vc 331 332 Ok(()) 333 } 334