xref: /DragonOS/kernel/src/driver/video/fbdev/base/fbcon/framebuffer_console.rs (revision e28411791f090c421fe4b6fa5956fb1bd362a8d9)
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 {
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 
43     pub fn fb(&self) -> Arc<dyn FrameBuffer> {
44         self.fb.lock().clone().unwrap()
45     }
46 
47     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     /// ## 计算单色调的函数
107     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 
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 {
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 
239     fn con_deinit(&self) -> Result<(), system_error::SystemError> {
240         todo!()
241     }
242 
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 
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 
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 
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 
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 
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     fn con_scroll(
395         &self,
396         vc_data: &mut VirtualConsoleData,
397         top: usize,
398         bottom: usize,
399         dir: crate::driver::tty::virtual_terminal::virtual_console::ScrollDir,
400         mut count: usize,
401     ) -> bool {
402         self.con_cursor(vc_data, CursorOperation::Erase);
403 
404         let fbcon_data = self.fbcon_data();
405         let scroll_mode = fbcon_data.display.scroll_mode;
406 
407         drop(fbcon_data);
408 
409         match dir {
410             ScrollDir::Up => {
411                 if count > vc_data.rows {
412                     count = vc_data.rows;
413                 }
414 
415                 match scroll_mode {
416                     ScrollMode::Move => {
417                         let start = top * vc_data.cols;
418                         let end = bottom * vc_data.cols;
419                         vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols);
420 
421                         let _ = self.bmove(
422                             vc_data,
423                             top as i32,
424                             0,
425                             top as i32 - count as i32,
426                             0,
427                             (bottom - top) as u32,
428                             vc_data.cols as u32,
429                         );
430 
431                         let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols);
432 
433                         let offset = vc_data.cols * (bottom - count);
434                         for i in
435                             vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
436                         {
437                             *i = vc_data.erase_char;
438                         }
439 
440                         return true;
441                     }
442                     ScrollMode::PanMove => todo!(),
443                     ScrollMode::WrapMove => todo!(),
444                     ScrollMode::Redraw => {
445                         let start = top * vc_data.cols;
446                         let end = bottom * vc_data.cols;
447                         vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols);
448 
449                         let data = &vc_data.screen_buf[start..(bottom - count) * vc_data.cols];
450 
451                         for line in top..(bottom - count) {
452                             let mut start = line * vc_data.cols;
453                             let end = start + vc_data.cols;
454                             let mut offset = start;
455                             let mut attr = 1;
456                             let mut x = 0;
457                             while offset < end {
458                                 let c = data[offset];
459 
460                                 if attr != c & 0xff00 {
461                                     // 属性变化,输出完上一个的并且更新属性
462                                     attr = c & 0xff00;
463 
464                                     let count = offset - start;
465                                     let _ = self.con_putcs(
466                                         vc_data,
467                                         &data[start..offset],
468                                         count,
469                                         line as u32,
470                                         x,
471                                     );
472                                     start = offset;
473                                     x += count as u32;
474                                 }
475 
476                                 offset += 1;
477                             }
478                             let _ = self.con_putcs(
479                                 vc_data,
480                                 &data[start..offset],
481                                 offset - start,
482                                 line as u32,
483                                 x,
484                             );
485                         }
486 
487                         let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols);
488 
489                         let offset = vc_data.cols * (bottom - count);
490                         for i in
491                             vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
492                         {
493                             *i = vc_data.erase_char;
494                         }
495 
496                         return true;
497                     }
498                     ScrollMode::PanRedraw => todo!(),
499                 }
500             }
501             ScrollDir::Down => {
502                 if count > vc_data.rows {
503                     count = vc_data.rows;
504                 }
505 
506                 match scroll_mode {
507                     ScrollMode::Move => todo!(),
508                     ScrollMode::PanMove => todo!(),
509                     ScrollMode::WrapMove => todo!(),
510                     ScrollMode::Redraw => {
511                         // self.scroll_redraw(
512                         //     vc_data,
513                         //     bottom - 1,
514                         //     bottom - top - count,
515                         //     count * vc_data.cols,
516                         //     false,
517                         // );
518 
519                         let _ = self.con_clear(vc_data, top, 0, count, vc_data.cols);
520 
521                         let offset = vc_data.cols * top;
522                         for i in
523                             vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
524                         {
525                             *i = vc_data.erase_char;
526                         }
527 
528                         return true;
529                     }
530                     ScrollMode::PanRedraw => todo!(),
531                 }
532             }
533         }
534     }
535 }
536 
537 impl FrameBufferConsole for BlittingFbConsole {
538     fn bmove(
539         &self,
540         vc_data: &VirtualConsoleData,
541         sy: i32,
542         sx: i32,
543         dy: i32,
544         dx: i32,
545         height: u32,
546         width: u32,
547     ) -> Result<(), SystemError> {
548         let area = CopyAreaData::new(
549             dx * vc_data.font.width as i32,
550             dy * vc_data.font.height as i32,
551             width * vc_data.font.width,
552             height * vc_data.font.height,
553             sx * vc_data.font.width as i32,
554             sy * vc_data.font.height as i32,
555         );
556 
557         self.fb().fb_copyarea(area)
558     }
559 
560     fn clear(
561         &self,
562         vc_data: &VirtualConsoleData,
563         sy: u32,
564         sx: u32,
565         height: u32,
566         width: u32,
567     ) -> Result<(), SystemError> {
568         let region = FillRectData::new(
569             sx * vc_data.font.width,
570             sy * vc_data.font.height,
571             width * vc_data.font.width,
572             height * vc_data.font.height,
573             self.get_color(vc_data, vc_data.erase_char, false),
574             FillRectROP::Copy,
575         );
576 
577         self.fb().fb_fillrect(region)?;
578 
579         Ok(())
580     }
581 
582     fn put_string(
583         &self,
584         vc_data: &VirtualConsoleData,
585         data: &[u16],
586         mut count: u32,
587         y: u32,
588         x: u32,
589         fg: u32,
590         bg: u32,
591     ) -> Result<(), SystemError> {
592         // 向上取整
593         let width = (vc_data.font.width + 7) / 8;
594         let cellsize = width * vc_data.font.height;
595         let fb_info = self.fb();
596         // 一次能输出的最大字数,避免帧缓冲区溢出
597         let max_cnt = (fb_info.current_fb_var().xres * fb_info.current_fb_var().yres) / cellsize;
598         let attr = FbConAttr::get_attr(data[0], fb_info.color_depth());
599 
600         let mut image = FbImage {
601             x: x * vc_data.font.width,
602             y: y * vc_data.font.height,
603             width: 0,
604             height: vc_data.font.height,
605             fg,
606             bg,
607             depth: 1,
608             data: Default::default(),
609         };
610 
611         image.data.resize(cellsize as usize * count as usize, 0);
612 
613         while count > 0 {
614             let cnt = count.min(max_cnt);
615 
616             image.width = vc_data.font.width * cnt;
617 
618             self.bit_put_string(vc_data, data, attr, cnt, cellsize, &mut image);
619 
620             image.x += cnt * vc_data.font.width;
621             count -= cnt;
622         }
623 
624         Ok(())
625     }
626 
627     fn fbcon_data(&self) -> SpinLockGuard<super::FrameBufferConsoleData> {
628         self.fbcon_data.lock()
629     }
630 
631     fn cursor(&self, vc_data: &VirtualConsoleData, op: CursorOperation, fg: u32, bg: u32) {
632         let mut fbcon_data = self.fbcon_data();
633         let fb_info = self.fb();
634         let mut cursor = FbCursor::default();
635         let charmask = if vc_data.hi_font_mask != 0 {
636             0x1ff
637         } else {
638             0xff
639         };
640 
641         // 向上取整
642         let w = (vc_data.font.width + 7) / 8;
643         let y = fbcon_data.display.real_y(vc_data.state.y as u32);
644 
645         let c = vc_data.screen_buf[vc_data.pos];
646         let attr = FbConAttr::get_attr(c, fb_info.color_depth());
647         let char_offset = (c as usize & charmask) * ((w * vc_data.font.height) as usize);
648 
649         if fbcon_data.cursor_state.image.data != &vc_data.font.data[char_offset..]
650             || fbcon_data.cursor_reset
651         {
652             fbcon_data.cursor_state.image.data = vc_data.font.data[char_offset..].to_vec();
653             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETIMAGE);
654         }
655 
656         if !attr.is_empty() {
657             fbcon_data
658                 .cursor_data
659                 .resize(w as usize * vc_data.font.height as usize, 0);
660 
661             attr.update_attr(
662                 &mut fbcon_data.cursor_data,
663                 &vc_data.font.data[char_offset..],
664                 vc_data,
665             );
666         }
667 
668         if fbcon_data.cursor_state.image.fg != fg
669             || fbcon_data.cursor_state.image.bg != bg
670             || fbcon_data.cursor_reset
671         {
672             fbcon_data.cursor_state.image.fg = fg;
673             fbcon_data.cursor_state.image.bg = bg;
674             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETCMAP);
675         }
676 
677         if fbcon_data.cursor_state.image.x != (vc_data.font.width * vc_data.state.x as u32)
678             || fbcon_data.cursor_state.image.y != (vc_data.font.height * y)
679             || fbcon_data.cursor_reset
680         {
681             fbcon_data.cursor_state.image.x = vc_data.font.width * vc_data.state.x as u32;
682             fbcon_data.cursor_state.image.y = vc_data.font.height * y;
683             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETPOS);
684         }
685 
686         if fbcon_data.cursor_state.image.height != vc_data.font.height
687             || fbcon_data.cursor_state.image.width != vc_data.font.width
688             || fbcon_data.cursor_reset
689         {
690             fbcon_data.cursor_state.image.height = vc_data.font.height;
691             fbcon_data.cursor_state.image.width = vc_data.font.width;
692             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSIZE);
693         }
694 
695         if fbcon_data.cursor_state.hot_x > 0
696             || fbcon_data.cursor_state.hot_y > 0
697             || fbcon_data.cursor_reset
698         {
699             fbcon_data.cursor_state.hot_x = 0;
700             cursor.hot_y = 0;
701             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETHOT);
702         }
703 
704         if cursor.set_mode.contains(FbCursorSetMode::FB_CUR_SETSIZE)
705             || vc_data.cursor_type != fbcon_data.display.cursor_shape
706             || fbcon_data.cursor_state.mask.is_empty()
707             || fbcon_data.cursor_reset
708         {
709             fbcon_data.display.cursor_shape = vc_data.cursor_type;
710             cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSHAPE);
711 
712             let cur_height;
713             match fbcon_data.display.cursor_shape.cursor_size() {
714                 VcCursor::CUR_NONE => {
715                     cur_height = 0;
716                 }
717                 VcCursor::CUR_UNDERLINE => {
718                     if vc_data.font.height < 10 {
719                         cur_height = 1;
720                     } else {
721                         cur_height = 2;
722                     }
723                 }
724                 VcCursor::CUR_LOWER_THIRD => {
725                     cur_height = vc_data.font.height / 3;
726                 }
727                 VcCursor::CUR_LOWER_HALF => {
728                     cur_height = vc_data.font.height >> 1;
729                 }
730                 VcCursor::CUR_TWO_THIRDS => {
731                     cur_height = (vc_data.font.height << 1) / 3;
732                 }
733                 _ => {
734                     cur_height = vc_data.font.height;
735                 }
736             }
737 
738             // 表示空白部分
739             let mut size = (vc_data.font.height - cur_height) * w;
740             while size > 0 {
741                 size -= 1;
742                 fbcon_data.cursor_state.mask.push(0x00);
743             }
744             size = cur_height * w;
745             // 表示光标显示部分
746             while size > 0 {
747                 size -= 1;
748                 fbcon_data.cursor_state.mask.push(0xff);
749             }
750         }
751 
752         match op {
753             CursorOperation::Erase => {
754                 fbcon_data.cursor_state.enable = false;
755             }
756             _ => {
757                 fbcon_data.cursor_state.enable = !vc_data.cursor_type.contains(VcCursor::CUR_SW);
758             }
759         }
760 
761         if !attr.is_empty() {
762             cursor.image.data = fbcon_data.cursor_data.clone();
763         } else {
764             cursor.image.data = vc_data.font.data
765                 [char_offset..char_offset + (w as usize * vc_data.font.height as usize)]
766                 .to_vec();
767         }
768         cursor.image.fg = fbcon_data.cursor_state.image.fg;
769         cursor.image.bg = fbcon_data.cursor_state.image.bg;
770         cursor.image.x = fbcon_data.cursor_state.image.x;
771         cursor.image.y = fbcon_data.cursor_state.image.y;
772         cursor.image.height = fbcon_data.cursor_state.image.height;
773         cursor.image.width = fbcon_data.cursor_state.image.width;
774         cursor.hot_x = fbcon_data.cursor_state.hot_x;
775         cursor.hot_y = fbcon_data.cursor_state.hot_y;
776         cursor.mask = fbcon_data.cursor_state.mask.clone();
777         cursor.enable = fbcon_data.cursor_state.enable;
778         cursor.image.depth = 1;
779         cursor.rop = true;
780 
781         if fb_info.fb_cursor(&cursor).is_err() {
782             let _ = fb_info.soft_cursor(cursor);
783         }
784 
785         fbcon_data.cursor_reset = false;
786     }
787 }
788