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