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