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 { 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 44 fn fb(&self) -> Arc<dyn FrameBuffer> { 45 self.fb.lock().clone().unwrap() 46 } 47 48 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 /// ## 计算单色调的函数 108 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 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 { 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 242 fn con_deinit(&self) -> Result<(), system_error::SystemError> { 243 todo!() 244 } 245 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 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 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 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)] 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 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)] 399 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 { 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 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 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 656 fn fbcon_data(&self) -> SpinLockGuard<super::FrameBufferConsoleData> { 657 self.fbcon_data.lock() 658 } 659 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