xref: /DragonOS/kernel/src/driver/tty/virtual_terminal/mod.rs (revision da152319797436368304cbc3f85a3b9ec049134b)
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: &[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         }
187 
188         if vc_data.utf {
189             tty_core.termios_write().input_mode.insert(InputMode::IUTF8);
190         } else {
191             tty_core.termios_write().input_mode.remove(InputMode::IUTF8);
192         }
193 
194         // 加入sysfs?
195 
196         Ok(())
197     }
198 
199     fn open(&self, _tty: &TtyCoreData) -> Result<(), SystemError> {
200         Ok(())
201     }
202 
203     fn write_room(&self, _tty: &TtyCoreData) -> usize {
204         32768
205     }
206 
207     /// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/tty/vt/vt.c#2894
208     #[inline(never)]
209     fn write(&self, tty: &TtyCoreData, buf: &[u8], nr: usize) -> Result<usize, SystemError> {
210         let ret = self.do_write(tty, buf, nr);
211         self.flush_chars(tty);
212         ret
213     }
214 
215     #[inline(never)]
216     fn flush_chars(&self, tty: &TtyCoreData) {
217         let mut vc_data = tty.vc_data_irqsave();
218         vc_data.set_cursor();
219     }
220 
221     fn put_char(&self, tty: &TtyCoreData, ch: u8) -> Result<(), SystemError> {
222         self.write(tty, &[ch], 1)?;
223         Ok(())
224     }
225 
226     fn ioctl(&self, _tty: Arc<TtyCore>, _cmd: u32, _arg: usize) -> Result<(), SystemError> {
227         // TODO
228         Err(SystemError::ENOIOCTLCMD)
229     }
230 }
231 
232 #[derive(Debug, Clone)]
233 pub struct VtModeData {
234     mode: VtMode,
235     /// 释放请求时触发的信号
236     relsig: u16,
237     /// 获取请求时触发的信号
238     acqsig: u16,
239 }
240 
241 #[allow(dead_code)]
242 #[derive(Debug, Clone)]
243 pub enum VtMode {
244     /// 自动切换模式,即在请求输入时自动切换到终端
245     Auto,
246     /// 手动切换模式,需要通过 ioctl 请求切换到终端
247     Process,
248     /// 等待终端确认,即在切换到终端时等待终端的确认信号
249     Ackacq,
250 }
251 
252 /// 用于给vc确定要写入的buf位置
253 #[derive(Debug, Default)]
254 pub struct DrawRegion {
255     /// 偏移量
256     pub offset: usize,
257     /// 写入数量
258     pub size: usize,
259     pub x: Option<u32>,
260 }
261 
262 // 初始化虚拟终端
263 #[inline(never)]
264 pub fn vty_init() -> Result<(), SystemError> {
265     // 注册虚拟终端设备并将虚拟终端设备加入到文件系统
266     let vc0 = TtyDevice::new(
267         "vc0",
268         IdTable::new(
269             String::from("vc0"),
270             Some(DeviceNumber::new(Major::TTY_MAJOR, 0)),
271         ),
272     );
273     // 注册tty设备
274     // CharDevOps::cdev_add(
275     //     vc0.clone() as Arc<dyn CharDevice>,
276     //     IdTable::new(
277     //         String::from("vc0"),
278     //         Some(DeviceNumber::new(Major::TTY_MAJOR, 0)),
279     //     ),
280     //     1,
281     // )?;
282 
283     // CharDevOps::register_chardev_region(DeviceNumber::new(Major::TTY_MAJOR, 0), 1, "/dev/vc/0")?;
284     device_register(vc0.clone())?;
285     devfs_register("vc0", vc0)?;
286 
287     // vcs_init?
288 
289     let console_driver = TtyDriver::new(
290         MAX_NR_CONSOLES,
291         "tty",
292         1,
293         Major::TTY_MAJOR,
294         0,
295         TtyDriverType::Console,
296         *TTY_STD_TERMIOS,
297         Arc::new(TtyConsoleDriverInner::new()?),
298     );
299 
300     TtyDriverManager::tty_register_driver(console_driver)?;
301 
302     CURRENT_VCNUM.store(0, Ordering::SeqCst);
303 
304     // 初始化键盘?
305 
306     // TODO: 为vc
307 
308     Ok(())
309 }
310