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 (1..=6).contains(&color) { 85 // 白色 86 color = 2; 87 } else if (7..=8).contains(&color) { 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, char_item) in buf.iter().enumerate().take(cnt as usize) { 142 // 在字符表中的index 143 let ch = char_item & 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![0; src.len()]; 151 dst.copy_from_slice(src); 152 153 if !attr.is_empty() { 154 attr.update_attr(&mut dst, src, vc_data) 155 } 156 157 offset = char_offset * byte_width; 158 let mut dst_offset = 0; 159 for _ in 0..font_height { 160 let dst_offset_next = dst_offset + byte_width; 161 image.data[offset..offset + byte_width] 162 .copy_from_slice(&dst[dst_offset..dst_offset_next]); 163 164 offset += image_line_byte; 165 dst_offset = dst_offset_next; 166 } 167 } 168 169 self.fb().fb_image_blit(image); 170 } 171 } 172 173 impl ConsoleSwitch for BlittingFbConsole { 174 fn con_init( 175 &self, 176 vc_data: &mut VirtualConsoleData, 177 init: bool, 178 ) -> Result<(), system_error::SystemError> { 179 let fb_set_guard = FRAME_BUFFER_SET.read(); 180 let fb = fb_set_guard.get(vc_data.index); 181 if fb.is_none() { 182 return Err(SystemError::EINVAL); 183 } 184 let fb = fb.unwrap(); 185 if fb.is_none() { 186 panic!( 187 "The Framebuffer with FbID {} has not been initialized yet.", 188 vc_data.index 189 ) 190 } 191 192 let fb = fb.as_ref().unwrap().clone(); 193 194 if init { 195 // 初始化字体 196 let var = fb.current_fb_var(); 197 let font = FontDesc::get_default_font(var.xres, var.yres, 0, 0); 198 vc_data.font.data = font.data.to_vec(); 199 vc_data.font.width = font.width; 200 vc_data.font.height = font.height; 201 vc_data.font.count = font.char_count; 202 } else { 203 kwarn!("The frontend Framebuffer is not implemented"); 204 } 205 206 vc_data.color_mode = fb.color_depth() != 1; 207 vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 }; 208 209 if vc_data.font.count == 256 { 210 // ascii 211 vc_data.hi_font_mask = 0; 212 } else { 213 vc_data.hi_font_mask = 0x100; 214 if vc_data.color_mode { 215 vc_data.complement_mask <<= 1; 216 } 217 } 218 219 // TODO: 考虑rotate 220 if init { 221 vc_data.cols = (fb.current_fb_var().xres / vc_data.font.width) as usize; 222 vc_data.rows = (fb.current_fb_var().yres / vc_data.font.height) as usize; 223 224 vc_data.pos = vc_data.state.x + vc_data.state.y * vc_data.cols; 225 226 let new_size = vc_data.cols * vc_data.rows; 227 vc_data.screen_buf.resize(new_size, 0); 228 } else { 229 unimplemented!("Resize is not supported at the moment!"); 230 } 231 232 // 初始化fb 233 *self.fb.lock() = Some(fb); 234 235 Ok(()) 236 } 237 238 fn con_deinit(&self) -> Result<(), system_error::SystemError> { 239 todo!() 240 } 241 242 fn con_clear( 243 &self, 244 vc_data: &mut VirtualConsoleData, 245 sy: usize, 246 sx: usize, 247 height: usize, 248 width: usize, 249 ) -> Result<(), system_error::SystemError> { 250 let fb_data = self.fbcon_data(); 251 252 if height == 0 || width == 0 { 253 return Ok(()); 254 } 255 256 let y_break = (fb_data.display.virt_rows - fb_data.display.yscroll) as usize; 257 if sy < y_break && sy + height > y_break { 258 // 分两次clear 259 let b = y_break - sy; 260 let _ = self.clear( 261 vc_data, 262 fb_data.display.real_y(sy as u32), 263 sx as u32, 264 b as u32, 265 width as u32, 266 ); 267 let _ = self.clear( 268 vc_data, 269 fb_data.display.real_y((sy + b) as u32), 270 sx as u32, 271 (height - b) as u32, 272 width as u32, 273 ); 274 } else { 275 let _ = self.clear( 276 vc_data, 277 fb_data.display.real_y(sy as u32), 278 sx as u32, 279 height as u32, 280 width as u32, 281 ); 282 } 283 284 Ok(()) 285 } 286 287 fn con_putc( 288 &self, 289 vc_data: &VirtualConsoleData, 290 ch: u16, 291 xpos: u32, 292 ypos: u32, 293 ) -> Result<(), system_error::SystemError> { 294 self.con_putcs(vc_data, &[ch], 1, ypos, xpos) 295 } 296 297 fn con_putcs( 298 &self, 299 vc_data: &VirtualConsoleData, 300 buf: &[u16], 301 count: usize, 302 ypos: u32, 303 xpos: u32, 304 ) -> Result<(), SystemError> { 305 if count == 0 { 306 return Ok(()); 307 } 308 let fbcon_data = self.fbcon_data(); 309 let c = buf[0]; 310 self.put_string( 311 vc_data, 312 buf, 313 count as u32, 314 fbcon_data.display.real_y(ypos), 315 xpos, 316 self.get_color(vc_data, c, true), 317 self.get_color(vc_data, c, false), 318 ) 319 } 320 321 fn con_getxy( 322 &self, 323 vc_data: &VirtualConsoleData, 324 pos: usize, 325 ) -> Result<(usize, usize, usize), SystemError> { 326 if pos < vc_data.screen_buf.len() { 327 let x = pos % vc_data.cols; 328 let y = pos / vc_data.cols; 329 let mut next_line_start = pos + (vc_data.cols - x); 330 if next_line_start >= vc_data.screen_buf.len() { 331 next_line_start = 0 332 } 333 return Ok((next_line_start, x, y)); 334 } else { 335 return Ok((0, 0, 0)); 336 } 337 } 338 339 #[allow(clippy::if_same_then_else)] 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