xref: /DragonOS/kernel/src/driver/tty/virtual_terminal/mod.rs (revision 9fab312ea9921618629924ab15c28c2d255b21c6)
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