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 #[inline(never)] 395 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 { 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 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 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 652 fn fbcon_data(&self) -> SpinLockGuard<super::FrameBufferConsoleData> { 653 self.fbcon_data.lock() 654 } 655 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