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