xref: /DragonOS/kernel/src/driver/video/fbdev/base/fbcon/framebuffer_console.rs (revision 59a6bcf6aee15a11a16431bdf875905c5ecf9157) !
1 use alloc::{sync::Arc, vec::Vec};
2 use log::warn;
3 use system_error::SystemError;
4 
5 use crate::{
6     driver::{
7         tty::{
8             console::ConsoleSwitch,
9             virtual_terminal::{
10                 virtual_console::{CursorOperation, ScrollDir, VcCursor, VirtualConsoleData},
11                 Color, VirtConsole,
12             },
13         },
14         video::fbdev::base::{
15             CopyAreaData, FbCursor, FbCursorSetMode, FbImage, FbVisual, FillRectData, FillRectROP,
16             FrameBuffer, ScrollMode, FRAME_BUFFER_SET,
17         },
18     },
19     libs::{
20         font::FontDesc,
21         spinlock::{SpinLock, SpinLockGuard},
22     },
23 };
24 
25 use super::{FbConAttr, FrameBufferConsole, FrameBufferConsoleData};
26 
27 #[derive(Debug)]
28 pub struct BlittingFbConsole {
29     fb: SpinLock<Option<Arc<dyn FrameBuffer>>>,
30     fbcon_data: SpinLock<FrameBufferConsoleData>,
31 }
32 
33 unsafe impl Send for BlittingFbConsole {}
34 unsafe impl Sync for BlittingFbConsole {}
35 
36 impl BlittingFbConsole {
new() -> Result<Self, SystemError>37     pub fn new() -> Result<Self, SystemError> {
38         Ok(Self {
39             fb: SpinLock::new(None),
40             fbcon_data: SpinLock::new(FrameBufferConsoleData::default()),
41         })
42     }
43 
fb(&self) -> Arc<dyn FrameBuffer>44     fn fb(&self) -> Arc<dyn FrameBuffer> {
45         self.fb.lock().clone().unwrap()
46     }
47 
get_color(&self, vc_data: &VirtualConsoleData, c: u16, is_fg: bool) -> u3248     fn get_color(&self, vc_data: &VirtualConsoleData, c: u16, is_fg: bool) -> u32 {
49         let fb_info = self.fb();
50         let mut color = 0;
51 
52         let depth = fb_info.color_depth();
53 
54         if depth != 1 {
55             if is_fg {
56                 let fg_shift = if vc_data.hi_font_mask != 0 { 9 } else { 8 };
57                 color = (c as u32 >> fg_shift) & 0x0f
58             } else {
59                 let bg_shift = if vc_data.hi_font_mask != 0 { 13 } else { 12 };
60                 color = (c as u32 >> bg_shift) & 0x0f
61             }
62         }
63 
64         match depth {
65             1 => {
66                 let col = self.mono_color();
67                 let fg;
68                 let bg;
69                 if fb_info.current_fb_fix().visual != FbVisual::Mono01 {
70                     fg = col;
71                     bg = 0;
72                 } else {
73                     fg = 0;
74                     bg = col;
75                 }
76                 color = if is_fg { fg } else { bg };
77             }
78             2 => {
79                 /*
80                     颜色深度为2,即16色,
81                    将16色的颜色值映射到4色的灰度,
82                    其中颜色0映射为黑色,颜色1到6映射为白色,
83                    颜色7到8映射为灰色,其他颜色映射为强烈的白色。
84                 */
85                 if (1..=6).contains(&color) {
86                     // 白色
87                     color = 2;
88                 } else if (7..=8).contains(&color) {
89                     // 灰色
90                     color = 1;
91                 } else {
92                     // 强白
93                     color = 3;
94                 }
95             }
96             3 => {
97                 /*
98                    颜色深度为3,即256色,仅保留颜色的低3位,即颜色 0 到 7
99                 */
100                 color &= 7;
101             }
102             _ => {}
103         }
104         color
105     }
106 
107     /// ## 计算单色调的函数
mono_color(&self) -> u32108     fn mono_color(&self) -> u32 {
109         let fb_info = self.fb();
110         let mut max_len = fb_info
111             .current_fb_var()
112             .green
113             .length
114             .max(fb_info.current_fb_var().red.length);
115 
116         max_len = max_len.max(fb_info.current_fb_var().blue.length);
117 
118         return (!(0xfff << max_len)) & 0xff;
119     }
120 
bit_put_string( &self, vc_data: &VirtualConsoleData, buf: &[u16], attr: FbConAttr, cnt: u32, cellsize: u32, image: &mut FbImage, )121     fn bit_put_string(
122         &self,
123         vc_data: &VirtualConsoleData,
124         buf: &[u16],
125         attr: FbConAttr,
126         cnt: u32,
127         cellsize: u32,
128         image: &mut FbImage,
129     ) {
130         let charmask = if vc_data.hi_font_mask != 0 {
131             0x1ff
132         } else {
133             0xff
134         };
135 
136         let mut offset;
137         let image_line_byte = image.width as usize / 8;
138 
139         let byte_width = vc_data.font.width as usize / 8;
140         let font_height = vc_data.font.height as usize;
141         // let mut char_offset = 0;
142         for (char_offset, char_item) in buf.iter().enumerate().take(cnt as usize) {
143             // 在字符表中的index
144             let ch = char_item & charmask;
145             // 计算出在font表中的偏移量
146             let font_offset = ch as usize * cellsize as usize;
147             let font_offset_end = font_offset + cellsize as usize;
148             // 设置image的data
149 
150             let src = &vc_data.font.data[font_offset..font_offset_end];
151             let mut dst = vec![0; src.len()];
152             dst.copy_from_slice(src);
153 
154             if !attr.is_empty() {
155                 attr.update_attr(&mut dst, src, vc_data)
156             }
157 
158             offset = char_offset * byte_width;
159             let mut dst_offset = 0;
160             for _ in 0..font_height {
161                 let dst_offset_next = dst_offset + byte_width;
162                 image.data[offset..offset + byte_width]
163                     .copy_from_slice(&dst[dst_offset..dst_offset_next]);
164 
165                 offset += image_line_byte;
166                 dst_offset = dst_offset_next;
167             }
168         }
169 
170         self.fb().fb_image_blit(image);
171     }
172 }
173 
174 impl ConsoleSwitch for BlittingFbConsole {
con_init( &self, _vc: &Arc<VirtConsole>, vc_data: &mut VirtualConsoleData, init: bool, ) -> Result<(), system_error::SystemError>175     fn con_init(
176         &self,
177         _vc: &Arc<VirtConsole>,
178         vc_data: &mut VirtualConsoleData,
179         init: bool,
180     ) -> Result<(), system_error::SystemError> {
181         let fb_set_guard = FRAME_BUFFER_SET.read();
182         let fb = fb_set_guard.get(vc_data.index);
183         if fb.is_none() {
184             return Err(SystemError::EINVAL);
185         }
186         let fb = fb.unwrap();
187         if fb.is_none() {
188             log::warn!(
189                 "The Framebuffer with FbID {} has not been initialized yet.",
190                 vc_data.index
191             );
192 
193             return Err(SystemError::ENODEV);
194         }
195 
196         let fb = fb.as_ref().unwrap().clone();
197 
198         if init {
199             // 初始化字体
200             let var = fb.current_fb_var();
201             let font = FontDesc::get_default_font(var.xres, var.yres, 0, 0);
202             vc_data.font.data = font.data.to_vec();
203             vc_data.font.width = font.width;
204             vc_data.font.height = font.height;
205             vc_data.font.count = font.char_count;
206         } else {
207             warn!("The frontend Framebuffer is not implemented");
208         }
209 
210         vc_data.color_mode = fb.color_depth() != 1;
211         vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 };
212 
213         if vc_data.font.count == 256 {
214             // ascii
215             vc_data.hi_font_mask = 0;
216         } else {
217             vc_data.hi_font_mask = 0x100;
218             if vc_data.color_mode {
219                 vc_data.complement_mask <<= 1;
220             }
221         }
222 
223         // TODO: 考虑rotate
224         if init {
225             vc_data.cols = (fb.current_fb_var().xres / vc_data.font.width) as usize;
226             vc_data.rows = (fb.current_fb_var().yres / vc_data.font.height) as usize;
227 
228             vc_data.pos = vc_data.state.x + vc_data.state.y * vc_data.cols;
229 
230             let new_size = vc_data.cols * vc_data.rows;
231             vc_data.screen_buf.resize(new_size, 0);
232         } else {
233             unimplemented!("Resize is not supported at the moment!");
234         }
235 
236         // 初始化fb
237         *self.fb.lock() = Some(fb);
238 
239         Ok(())
240     }
241 
con_deinit(&self) -> Result<(), system_error::SystemError>242     fn con_deinit(&self) -> Result<(), system_error::SystemError> {
243         todo!()
244     }
245 
con_clear( &self, vc_data: &mut VirtualConsoleData, sy: usize, sx: usize, height: usize, width: usize, ) -> Result<(), system_error::SystemError>246     fn con_clear(
247         &self,
248         vc_data: &mut VirtualConsoleData,
249         sy: usize,
250         sx: usize,
251         height: usize,
252         width: usize,
253     ) -> Result<(), system_error::SystemError> {
254         let fb_data = self.fbcon_data();
255 
256         if height == 0 || width == 0 {
257             return Ok(());
258         }
259 
260         let y_break = (fb_data.display.virt_rows - fb_data.display.yscroll) as usize;
261         if sy < y_break && sy + height > y_break {
262             // 分两次clear
263             let b = y_break - sy;
264             let _ = self.clear(
265                 vc_data,
266                 fb_data.display.real_y(sy as u32),
267                 sx as u32,
268                 b as u32,
269                 width as u32,
270             );
271             let _ = self.clear(
272                 vc_data,
273                 fb_data.display.real_y((sy + b) as u32),
274                 sx as u32,
275                 (height - b) as u32,
276                 width as u32,
277             );
278         } else {
279             let _ = self.clear(
280                 vc_data,
281                 fb_data.display.real_y(sy as u32),
282                 sx as u32,
283                 height as u32,
284                 width as u32,
285             );
286         }
287 
288         Ok(())
289     }
290 
con_putc( &self, vc_data: &VirtualConsoleData, ch: u16, xpos: u32, ypos: u32, ) -> Result<(), system_error::SystemError>291     fn con_putc(
292         &self,
293         vc_data: &VirtualConsoleData,
294         ch: u16,
295         xpos: u32,
296         ypos: u32,
297     ) -> Result<(), system_error::SystemError> {
298         self.con_putcs(vc_data, &[ch], 1, ypos, xpos)
299     }
300 
con_putcs( &self, vc_data: &VirtualConsoleData, buf: &[u16], count: usize, ypos: u32, xpos: u32, ) -> Result<(), SystemError>301     fn con_putcs(
302         &self,
303         vc_data: &VirtualConsoleData,
304         buf: &[u16],
305         count: usize,
306         ypos: u32,
307         xpos: u32,
308     ) -> Result<(), SystemError> {
309         if count == 0 {
310             return Ok(());
311         }
312         let fbcon_data = self.fbcon_data();
313         let c = buf[0];
314         self.put_string(
315             vc_data,
316             buf,
317             count as u32,
318             fbcon_data.display.real_y(ypos),
319             xpos,
320             self.get_color(vc_data, c, true),
321             self.get_color(vc_data, c, false),
322         )
323     }
324 
con_getxy( &self, vc_data: &VirtualConsoleData, pos: usize, ) -> Result<(usize, usize, usize), SystemError>325     fn con_getxy(
326         &self,
327         vc_data: &VirtualConsoleData,
328         pos: usize,
329     ) -> Result<(usize, usize, usize), SystemError> {
330         if pos < vc_data.screen_buf.len() {
331             let x = pos % vc_data.cols;
332             let y = pos / vc_data.cols;
333             let mut next_line_start = pos + (vc_data.cols - x);
334             if next_line_start >= vc_data.screen_buf.len() {
335                 next_line_start = 0
336             }
337             return Ok((next_line_start, x, y));
338         } else {
339             return Ok((0, 0, 0));
340         }
341     }
342 
343     #[allow(clippy::if_same_then_else)]
con_cursor( &self, vc_data: &VirtualConsoleData, op: crate::driver::tty::virtual_terminal::virtual_console::CursorOperation, )344     fn con_cursor(
345         &self,
346         vc_data: &VirtualConsoleData,
347         op: crate::driver::tty::virtual_terminal::virtual_console::CursorOperation,
348     ) {
349         let mut fbcon_data = self.fbcon_data();
350 
351         let c = vc_data.screen_buf[vc_data.pos];
352 
353         if vc_data.cursor_type.contains(VcCursor::CUR_SW) {
354             // 取消硬光标Timer,但是现在没有硬光标,先写在这
355         } else {
356             // 添加硬光标Timer
357         }
358 
359         fbcon_data.cursor_flash = op != CursorOperation::Erase;
360 
361         drop(fbcon_data);
362 
363         self.cursor(
364             vc_data,
365             op,
366             self.get_color(vc_data, c, true),
367             self.get_color(vc_data, c, false),
368         );
369     }
370 
con_set_palette( &self, vc_data: &VirtualConsoleData, color_table: &[u8], ) -> Result<(), SystemError>371     fn con_set_palette(
372         &self,
373         vc_data: &VirtualConsoleData,
374         color_table: &[u8],
375     ) -> Result<(), SystemError> {
376         let fb_info = self.fb();
377         let depth = fb_info.color_depth();
378         let mut palette = Vec::new();
379         palette.resize(16, Color::default());
380         if depth > 3 {
381             let vc_palette = &vc_data.palette;
382             for i in 0..16 {
383                 let idx = color_table[i];
384                 let col = palette.get_mut(idx as usize).unwrap();
385                 col.red = (vc_palette[i].red << 8) | vc_palette[i].red;
386                 col.green = (vc_palette[i].green << 8) | vc_palette[i].green;
387                 col.blue = (vc_palette[i].blue << 8) | vc_palette[i].blue;
388             }
389         } else {
390             todo!()
391         }
392 
393         self.fb().set_color_map(palette)?;
394 
395         Ok(())
396     }
397 
398     #[inline(never)]
con_scroll( &self, vc_data: &mut VirtualConsoleData, top: usize, bottom: usize, dir: crate::driver::tty::virtual_terminal::virtual_console::ScrollDir, mut count: usize, ) -> bool399     fn con_scroll(
400         &self,
401         vc_data: &mut VirtualConsoleData,
402         top: usize,
403         bottom: usize,
404         dir: crate::driver::tty::virtual_terminal::virtual_console::ScrollDir,
405         mut count: usize,
406     ) -> bool {
407         self.con_cursor(vc_data, CursorOperation::Erase);
408 
409         let fbcon_data = self.fbcon_data();
410         let scroll_mode = fbcon_data.display.scroll_mode;
411 
412         drop(fbcon_data);
413 
414         match dir {
415             ScrollDir::Up => {
416                 if count > vc_data.rows {
417                     count = vc_data.rows;
418                 }
419 
420                 match scroll_mode {
421                     ScrollMode::Move => {
422                         let start = top * vc_data.cols;
423                         let end = bottom * vc_data.cols;
424                         vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols);
425 
426                         let _ = self.bmove(
427                             vc_data,
428                             top as i32,
429                             0,
430                             top as i32 - count as i32,
431                             0,
432                             (bottom - top) as u32,
433                             vc_data.cols as u32,
434                         );
435 
436                         let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols);
437 
438                         let offset = vc_data.cols * (bottom - count);
439                         for i in
440                             vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
441                         {
442                             *i = vc_data.erase_char;
443                         }
444 
445                         return true;
446                     }
447                     ScrollMode::PanMove => todo!(),
448                     ScrollMode::WrapMove => todo!(),
449                     ScrollMode::Redraw => {
450                         let start = top * vc_data.cols;
451                         let end = bottom * vc_data.cols;
452                         vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols);
453 
454                         let data = &vc_data.screen_buf[start..(bottom - count) * vc_data.cols];
455 
456                         for line in top..(bottom - count) {
457                             let mut start = line * vc_data.cols;
458                             let end = start + vc_data.cols;
459                             let mut offset = start;
460                             let mut attr = 1;
461                             let mut x = 0;
462                             while offset < end {
463                                 let c = data[offset];
464 
465                                 if attr != c & 0xff00 {
466                                     // 属性变化,输出完上一个的并且更新属性
467                                     attr = c & 0xff00;
468 
469                                     let count = offset - start;
470                                     let _ = self.con_putcs(
471                                         vc_data,
472                                         &data[start..offset],
473                                         count,
474                                         line as u32,
475                                         x,
476                                     );
477                                     start = offset;
478                                     x += count as u32;
479                                 }
480 
481                                 offset += 1;
482                             }
483                             let _ = self.con_putcs(
484                                 vc_data,
485                                 &data[start..offset],
486                                 offset - start,
487                                 line as u32,
488                                 x,
489                             );
490                         }
491 
492                         let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols);
493 
494                         let offset = vc_data.cols * (bottom - count);
495                         for i in
496                             vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
497                         {
498                             *i = vc_data.erase_char;
499                         }
500 
501                         return true;
502                     }
503                     ScrollMode::PanRedraw => todo!(),
504                 }
505             }
506             ScrollDir::Down => {
507                 if count > vc_data.rows {
508                     count = vc_data.rows;
509                 }
510 
511                 match scroll_mode {
512                     ScrollMode::Move => {
513                         let start = top * vc_data.cols;
514                         let end = bottom * vc_data.cols;
515                         vc_data.screen_buf[start..end].rotate_right(count * vc_data.cols);
516 
517                         let _ = self.bmove(
518                             vc_data,
519                             top as i32,
520                             0,
521                             top as i32 + count as i32,
522                             0,
523                             (bottom - top - count) as u32,
524                             vc_data.cols as u32,
525                         );
526 
527                         let _ = self.con_clear(vc_data, top, 0, count, vc_data.cols);
528 
529                         let offset = vc_data.cols * count;
530                         for i in vc_data.screen_buf[start..(start + offset)].iter_mut() {
531                             *i = vc_data.erase_char;
532                         }
533 
534                         return true;
535                     }
536                     ScrollMode::PanMove => todo!(),
537                     ScrollMode::WrapMove => todo!(),
538                     ScrollMode::Redraw => {
539                         // self.scroll_redraw(
540                         //     vc_data,
541                         //     bottom - 1,
542                         //     bottom - top - count,
543                         //     count * vc_data.cols,
544                         //     false,
545                         // );
546 
547                         let _ = self.con_clear(vc_data, top, 0, count, vc_data.cols);
548 
549                         let offset = vc_data.cols * top;
550                         for i in
551                             vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
552                         {
553                             *i = vc_data.erase_char;
554                         }
555 
556                         return true;
557                     }
558                     ScrollMode::PanRedraw => todo!(),
559                 }
560             }
561         }
562     }
563 }
564 
565 impl FrameBufferConsole for BlittingFbConsole {
bmove( &self, vc_data: &VirtualConsoleData, sy: i32, sx: i32, dy: i32, dx: i32, height: u32, width: u32, ) -> Result<(), SystemError>566     fn bmove(
567         &self,
568         vc_data: &VirtualConsoleData,
569         sy: i32,
570         sx: i32,
571         dy: i32,
572         dx: i32,
573         height: u32,
574         width: u32,
575     ) -> Result<(), SystemError> {
576         let area = CopyAreaData::new(
577             dx * vc_data.font.width as i32,
578             dy * vc_data.font.height as i32,
579             width * vc_data.font.width,
580             height * vc_data.font.height,
581             sx * vc_data.font.width as i32,
582             sy * vc_data.font.height as i32,
583         );
584 
585         self.fb().fb_copyarea(area);
586         Ok(())
587     }
588 
clear( &self, vc_data: &VirtualConsoleData, sy: u32, sx: u32, height: u32, width: u32, ) -> Result<(), SystemError>589     fn clear(
590         &self,
591         vc_data: &VirtualConsoleData,
592         sy: u32,
593         sx: u32,
594         height: u32,
595         width: u32,
596     ) -> Result<(), SystemError> {
597         let region = FillRectData::new(
598             sx * vc_data.font.width,
599             sy * vc_data.font.height,
600             width * vc_data.font.width,
601             height * vc_data.font.height,
602             self.get_color(vc_data, vc_data.erase_char, false),
603             FillRectROP::Copy,
604         );
605 
606         self.fb().fb_fillrect(region)?;
607 
608         Ok(())
609     }
610 
put_string( &self, vc_data: &VirtualConsoleData, data: &[u16], mut count: u32, y: u32, x: u32, fg: u32, bg: u32, ) -> Result<(), SystemError>611     fn put_string(
612         &self,
613         vc_data: &VirtualConsoleData,
614         data: &[u16],
615         mut count: u32,
616         y: u32,
617         x: u32,
618         fg: u32,
619         bg: u32,
620     ) -> Result<(), SystemError> {
621         // 向上取整
622         let width = (vc_data.font.width + 7) / 8;
623         let cellsize = width * vc_data.font.height;
624         let fb_info = self.fb();
625         // 一次能输出的最大字数,避免帧缓冲区溢出
626         let max_cnt = (fb_info.current_fb_var().xres * fb_info.current_fb_var().yres) / cellsize;
627         let attr = FbConAttr::get_attr(data[0], fb_info.color_depth());
628 
629         let mut image = FbImage {
630             x: x * vc_data.font.width,
631             y: y * vc_data.font.height,
632             width: 0,
633             height: vc_data.font.height,
634             fg,
635             bg,
636             depth: 1,
637             data: Default::default(),
638         };
639 
640         image.data.resize(cellsize as usize * count as usize, 0);
641 
642         while count > 0 {
643             let cnt = count.min(max_cnt);
644 
645             image.width = vc_data.font.width * cnt;
646 
647             self.bit_put_string(vc_data, data, attr, cnt, cellsize, &mut image);
648 
649             image.x += cnt * vc_data.font.width;
650             count -= cnt;
651         }
652 
653         Ok(())
654     }
655 
fbcon_data(&self) -> SpinLockGuard<super::FrameBufferConsoleData>656     fn fbcon_data(&self) -> SpinLockGuard<super::FrameBufferConsoleData> {
657         self.fbcon_data.lock()
658     }
659 
cursor(&self, vc_data: &VirtualConsoleData, op: CursorOperation, fg: u32, bg: u32)660     fn cursor(&self, vc_data: &VirtualConsoleData, op: CursorOperation, fg: u32, bg: u32) {
661         let mut fbcon_data = self.fbcon_data();
662         let fb_info = self.fb();
663         let mut cursor = FbCursor::default();
664         let charmask = if vc_data.hi_font_mask != 0 {
665             0x1ff
666         } else {
667             0xff
668         };
669 
670         // 向上取整
671         let w = (vc_data.font.width + 7) / 8;
672         let y = fbcon_data.display.real_y(vc_data.state.y as u32);
673 
674         let c = vc_data.screen_buf[vc_data.pos];
675         let attr = FbConAttr::get_attr(c, fb_info.color_depth());
676         let char_offset = (c as usize & charmask) * ((w * vc_data.font.height) as usize);
677 
678         if fbcon_data.cursor_state.image.data != vc_data.font.data[char_offset..]
679             || fbcon_data.cursor_reset
680         {
681             fbcon_data.cursor_state.image.data = vc_data.font.data[char_offset..].to_vec();
682             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETIMAGE);
683         }
684 
685         if !attr.is_empty() {
686             fbcon_data
687                 .cursor_data
688                 .resize(w as usize * vc_data.font.height as usize, 0);
689 
690             attr.update_attr(
691                 &mut fbcon_data.cursor_data,
692                 &vc_data.font.data[char_offset..],
693                 vc_data,
694             );
695         }
696 
697         if fbcon_data.cursor_state.image.fg != fg
698             || fbcon_data.cursor_state.image.bg != bg
699             || fbcon_data.cursor_reset
700         {
701             fbcon_data.cursor_state.image.fg = fg;
702             fbcon_data.cursor_state.image.bg = bg;
703             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETCMAP);
704         }
705 
706         if fbcon_data.cursor_state.image.x != (vc_data.font.width * vc_data.state.x as u32)
707             || fbcon_data.cursor_state.image.y != (vc_data.font.height * y)
708             || fbcon_data.cursor_reset
709         {
710             fbcon_data.cursor_state.image.x = vc_data.font.width * vc_data.state.x as u32;
711             fbcon_data.cursor_state.image.y = vc_data.font.height * y;
712             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETPOS);
713         }
714 
715         if fbcon_data.cursor_state.image.height != vc_data.font.height
716             || fbcon_data.cursor_state.image.width != vc_data.font.width
717             || fbcon_data.cursor_reset
718         {
719             fbcon_data.cursor_state.image.height = vc_data.font.height;
720             fbcon_data.cursor_state.image.width = vc_data.font.width;
721             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSIZE);
722         }
723 
724         if fbcon_data.cursor_state.hot_x > 0
725             || fbcon_data.cursor_state.hot_y > 0
726             || fbcon_data.cursor_reset
727         {
728             fbcon_data.cursor_state.hot_x = 0;
729             cursor.hot_y = 0;
730             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETHOT);
731         }
732 
733         if cursor.set_mode.contains(FbCursorSetMode::FB_CUR_SETSIZE)
734             || vc_data.cursor_type != fbcon_data.display.cursor_shape
735             || fbcon_data.cursor_state.mask.is_empty()
736             || fbcon_data.cursor_reset
737         {
738             fbcon_data.display.cursor_shape = vc_data.cursor_type;
739             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSHAPE);
740 
741             let cur_height;
742             match fbcon_data.display.cursor_shape.cursor_size() {
743                 VcCursor::CUR_NONE => {
744                     cur_height = 0;
745                 }
746                 VcCursor::CUR_UNDERLINE => {
747                     if vc_data.font.height < 10 {
748                         cur_height = 1;
749                     } else {
750                         cur_height = 2;
751                     }
752                 }
753                 VcCursor::CUR_LOWER_THIRD => {
754                     cur_height = vc_data.font.height / 3;
755                 }
756                 VcCursor::CUR_LOWER_HALF => {
757                     cur_height = vc_data.font.height >> 1;
758                 }
759                 VcCursor::CUR_TWO_THIRDS => {
760                     cur_height = (vc_data.font.height << 1) / 3;
761                 }
762                 _ => {
763                     cur_height = vc_data.font.height;
764                 }
765             }
766 
767             // 表示空白部分
768             let mut size = (vc_data.font.height - cur_height) * w;
769             while size > 0 {
770                 size -= 1;
771                 fbcon_data.cursor_state.mask.push(0x00);
772             }
773             size = cur_height * w;
774             // 表示光标显示部分
775             while size > 0 {
776                 size -= 1;
777                 fbcon_data.cursor_state.mask.push(0xff);
778             }
779         }
780 
781         match op {
782             CursorOperation::Erase => {
783                 fbcon_data.cursor_state.enable = false;
784             }
785             _ => {
786                 fbcon_data.cursor_state.enable = !vc_data.cursor_type.contains(VcCursor::CUR_SW);
787             }
788         }
789 
790         if !attr.is_empty() {
791             cursor.image.data = fbcon_data.cursor_data.clone();
792         } else {
793             cursor.image.data = vc_data.font.data
794                 [char_offset..char_offset + (w as usize * vc_data.font.height as usize)]
795                 .to_vec();
796         }
797         cursor.image.fg = fbcon_data.cursor_state.image.fg;
798         cursor.image.bg = fbcon_data.cursor_state.image.bg;
799         cursor.image.x = fbcon_data.cursor_state.image.x;
800         cursor.image.y = fbcon_data.cursor_state.image.y;
801         cursor.image.height = fbcon_data.cursor_state.image.height;
802         cursor.image.width = fbcon_data.cursor_state.image.width;
803         cursor.hot_x = fbcon_data.cursor_state.hot_x;
804         cursor.hot_y = fbcon_data.cursor_state.hot_y;
805         cursor.mask = fbcon_data.cursor_state.mask.clone();
806         cursor.enable = fbcon_data.cursor_state.enable;
807         cursor.image.depth = 1;
808         cursor.rop = true;
809 
810         if fb_info.fb_cursor(&cursor).is_err() {
811             let _ = fb_info.soft_cursor(cursor);
812         }
813 
814         fbcon_data.cursor_reset = false;
815     }
816 }
817