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 panic!( 189 "The Framebuffer with FbID {} has not been initialized yet.", 190 vc_data.index 191 ) 192 } 193 194 let fb = fb.as_ref().unwrap().clone(); 195 196 if init { 197 // 初始化字体 198 let var = fb.current_fb_var(); 199 let font = FontDesc::get_default_font(var.xres, var.yres, 0, 0); 200 vc_data.font.data = font.data.to_vec(); 201 vc_data.font.width = font.width; 202 vc_data.font.height = font.height; 203 vc_data.font.count = font.char_count; 204 } else { 205 warn!("The frontend Framebuffer is not implemented"); 206 } 207 208 vc_data.color_mode = fb.color_depth() != 1; 209 vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 }; 210 211 if vc_data.font.count == 256 { 212 // ascii 213 vc_data.hi_font_mask = 0; 214 } else { 215 vc_data.hi_font_mask = 0x100; 216 if vc_data.color_mode { 217 vc_data.complement_mask <<= 1; 218 } 219 } 220 221 // TODO: 考虑rotate 222 if init { 223 vc_data.cols = (fb.current_fb_var().xres / vc_data.font.width) as usize; 224 vc_data.rows = (fb.current_fb_var().yres / vc_data.font.height) as usize; 225 226 vc_data.pos = vc_data.state.x + vc_data.state.y * vc_data.cols; 227 228 let new_size = vc_data.cols * vc_data.rows; 229 vc_data.screen_buf.resize(new_size, 0); 230 } else { 231 unimplemented!("Resize is not supported at the moment!"); 232 } 233 234 // 初始化fb 235 *self.fb.lock() = Some(fb); 236 237 Ok(()) 238 } 239 240 fn con_deinit(&self) -> Result<(), system_error::SystemError> { 241 todo!() 242 } 243 244 fn con_clear( 245 &self, 246 vc_data: &mut VirtualConsoleData, 247 sy: usize, 248 sx: usize, 249 height: usize, 250 width: usize, 251 ) -> Result<(), system_error::SystemError> { 252 let fb_data = self.fbcon_data(); 253 254 if height == 0 || width == 0 { 255 return Ok(()); 256 } 257 258 let y_break = (fb_data.display.virt_rows - fb_data.display.yscroll) as usize; 259 if sy < y_break && sy + height > y_break { 260 // 分两次clear 261 let b = y_break - sy; 262 let _ = self.clear( 263 vc_data, 264 fb_data.display.real_y(sy as u32), 265 sx as u32, 266 b as u32, 267 width as u32, 268 ); 269 let _ = self.clear( 270 vc_data, 271 fb_data.display.real_y((sy + b) as u32), 272 sx as u32, 273 (height - b) as u32, 274 width as u32, 275 ); 276 } else { 277 let _ = self.clear( 278 vc_data, 279 fb_data.display.real_y(sy as u32), 280 sx as u32, 281 height as u32, 282 width as u32, 283 ); 284 } 285 286 Ok(()) 287 } 288 289 fn con_putc( 290 &self, 291 vc_data: &VirtualConsoleData, 292 ch: u16, 293 xpos: u32, 294 ypos: u32, 295 ) -> Result<(), system_error::SystemError> { 296 self.con_putcs(vc_data, &[ch], 1, ypos, xpos) 297 } 298 299 fn con_putcs( 300 &self, 301 vc_data: &VirtualConsoleData, 302 buf: &[u16], 303 count: usize, 304 ypos: u32, 305 xpos: u32, 306 ) -> Result<(), SystemError> { 307 if count == 0 { 308 return Ok(()); 309 } 310 let fbcon_data = self.fbcon_data(); 311 let c = buf[0]; 312 self.put_string( 313 vc_data, 314 buf, 315 count as u32, 316 fbcon_data.display.real_y(ypos), 317 xpos, 318 self.get_color(vc_data, c, true), 319 self.get_color(vc_data, c, false), 320 ) 321 } 322 323 fn con_getxy( 324 &self, 325 vc_data: &VirtualConsoleData, 326 pos: usize, 327 ) -> Result<(usize, usize, usize), SystemError> { 328 if pos < vc_data.screen_buf.len() { 329 let x = pos % vc_data.cols; 330 let y = pos / vc_data.cols; 331 let mut next_line_start = pos + (vc_data.cols - x); 332 if next_line_start >= vc_data.screen_buf.len() { 333 next_line_start = 0 334 } 335 return Ok((next_line_start, x, y)); 336 } else { 337 return Ok((0, 0, 0)); 338 } 339 } 340 341 #[allow(clippy::if_same_then_else)] 342 fn con_cursor( 343 &self, 344 vc_data: &VirtualConsoleData, 345 op: crate::driver::tty::virtual_terminal::virtual_console::CursorOperation, 346 ) { 347 let mut fbcon_data = self.fbcon_data(); 348 349 let c = vc_data.screen_buf[vc_data.pos]; 350 351 if vc_data.cursor_type.contains(VcCursor::CUR_SW) { 352 // 取消硬光标Timer,但是现在没有硬光标,先写在这 353 } else { 354 // 添加硬光标Timer 355 } 356 357 fbcon_data.cursor_flash = op != CursorOperation::Erase; 358 359 drop(fbcon_data); 360 361 self.cursor( 362 vc_data, 363 op, 364 self.get_color(vc_data, c, true), 365 self.get_color(vc_data, c, false), 366 ); 367 } 368 369 fn con_set_palette( 370 &self, 371 vc_data: &VirtualConsoleData, 372 color_table: &[u8], 373 ) -> Result<(), SystemError> { 374 let fb_info = self.fb(); 375 let depth = fb_info.color_depth(); 376 let mut palette = Vec::new(); 377 palette.resize(16, Color::default()); 378 if depth > 3 { 379 let vc_palette = &vc_data.palette; 380 for i in 0..16 { 381 let idx = color_table[i]; 382 let col = palette.get_mut(idx as usize).unwrap(); 383 col.red = (vc_palette[i].red << 8) | vc_palette[i].red; 384 col.green = (vc_palette[i].green << 8) | vc_palette[i].green; 385 col.blue = (vc_palette[i].blue << 8) | vc_palette[i].blue; 386 } 387 } else { 388 todo!() 389 } 390 391 self.fb().set_color_map(palette)?; 392 393 Ok(()) 394 } 395 396 #[inline(never)] 397 fn con_scroll( 398 &self, 399 vc_data: &mut VirtualConsoleData, 400 top: usize, 401 bottom: usize, 402 dir: crate::driver::tty::virtual_terminal::virtual_console::ScrollDir, 403 mut count: usize, 404 ) -> bool { 405 self.con_cursor(vc_data, CursorOperation::Erase); 406 407 let fbcon_data = self.fbcon_data(); 408 let scroll_mode = fbcon_data.display.scroll_mode; 409 410 drop(fbcon_data); 411 412 match dir { 413 ScrollDir::Up => { 414 if count > vc_data.rows { 415 count = vc_data.rows; 416 } 417 418 match scroll_mode { 419 ScrollMode::Move => { 420 let start = top * vc_data.cols; 421 let end = bottom * vc_data.cols; 422 vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols); 423 424 let _ = self.bmove( 425 vc_data, 426 top as i32, 427 0, 428 top as i32 - count as i32, 429 0, 430 (bottom - top) as u32, 431 vc_data.cols as u32, 432 ); 433 434 let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols); 435 436 let offset = vc_data.cols * (bottom - count); 437 for i in 438 vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut() 439 { 440 *i = vc_data.erase_char; 441 } 442 443 return true; 444 } 445 ScrollMode::PanMove => todo!(), 446 ScrollMode::WrapMove => todo!(), 447 ScrollMode::Redraw => { 448 let start = top * vc_data.cols; 449 let end = bottom * vc_data.cols; 450 vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols); 451 452 let data = &vc_data.screen_buf[start..(bottom - count) * vc_data.cols]; 453 454 for line in top..(bottom - count) { 455 let mut start = line * vc_data.cols; 456 let end = start + vc_data.cols; 457 let mut offset = start; 458 let mut attr = 1; 459 let mut x = 0; 460 while offset < end { 461 let c = data[offset]; 462 463 if attr != c & 0xff00 { 464 // 属性变化,输出完上一个的并且更新属性 465 attr = c & 0xff00; 466 467 let count = offset - start; 468 let _ = self.con_putcs( 469 vc_data, 470 &data[start..offset], 471 count, 472 line as u32, 473 x, 474 ); 475 start = offset; 476 x += count as u32; 477 } 478 479 offset += 1; 480 } 481 let _ = self.con_putcs( 482 vc_data, 483 &data[start..offset], 484 offset - start, 485 line as u32, 486 x, 487 ); 488 } 489 490 let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols); 491 492 let offset = vc_data.cols * (bottom - count); 493 for i in 494 vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut() 495 { 496 *i = vc_data.erase_char; 497 } 498 499 return true; 500 } 501 ScrollMode::PanRedraw => todo!(), 502 } 503 } 504 ScrollDir::Down => { 505 if count > vc_data.rows { 506 count = vc_data.rows; 507 } 508 509 match scroll_mode { 510 ScrollMode::Move => { 511 let start = top * vc_data.cols; 512 let end = bottom * vc_data.cols; 513 vc_data.screen_buf[start..end].rotate_right(count * vc_data.cols); 514 515 let _ = self.bmove( 516 vc_data, 517 top as i32, 518 0, 519 top as i32 + count as i32, 520 0, 521 (bottom - top - count) as u32, 522 vc_data.cols as u32, 523 ); 524 525 let _ = self.con_clear(vc_data, top, 0, count, vc_data.cols); 526 527 let offset = vc_data.cols * count; 528 for i in vc_data.screen_buf[start..(start + offset)].iter_mut() { 529 *i = vc_data.erase_char; 530 } 531 532 return true; 533 } 534 ScrollMode::PanMove => todo!(), 535 ScrollMode::WrapMove => todo!(), 536 ScrollMode::Redraw => { 537 // self.scroll_redraw( 538 // vc_data, 539 // bottom - 1, 540 // bottom - top - count, 541 // count * vc_data.cols, 542 // false, 543 // ); 544 545 let _ = self.con_clear(vc_data, top, 0, count, vc_data.cols); 546 547 let offset = vc_data.cols * top; 548 for i in 549 vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut() 550 { 551 *i = vc_data.erase_char; 552 } 553 554 return true; 555 } 556 ScrollMode::PanRedraw => todo!(), 557 } 558 } 559 } 560 } 561 } 562 563 impl FrameBufferConsole for BlittingFbConsole { 564 fn bmove( 565 &self, 566 vc_data: &VirtualConsoleData, 567 sy: i32, 568 sx: i32, 569 dy: i32, 570 dx: i32, 571 height: u32, 572 width: u32, 573 ) -> Result<(), SystemError> { 574 let area = CopyAreaData::new( 575 dx * vc_data.font.width as i32, 576 dy * vc_data.font.height as i32, 577 width * vc_data.font.width, 578 height * vc_data.font.height, 579 sx * vc_data.font.width as i32, 580 sy * vc_data.font.height as i32, 581 ); 582 583 self.fb().fb_copyarea(area); 584 Ok(()) 585 } 586 587 fn clear( 588 &self, 589 vc_data: &VirtualConsoleData, 590 sy: u32, 591 sx: u32, 592 height: u32, 593 width: u32, 594 ) -> Result<(), SystemError> { 595 let region = FillRectData::new( 596 sx * vc_data.font.width, 597 sy * vc_data.font.height, 598 width * vc_data.font.width, 599 height * vc_data.font.height, 600 self.get_color(vc_data, vc_data.erase_char, false), 601 FillRectROP::Copy, 602 ); 603 604 self.fb().fb_fillrect(region)?; 605 606 Ok(()) 607 } 608 609 fn put_string( 610 &self, 611 vc_data: &VirtualConsoleData, 612 data: &[u16], 613 mut count: u32, 614 y: u32, 615 x: u32, 616 fg: u32, 617 bg: u32, 618 ) -> Result<(), SystemError> { 619 // 向上取整 620 let width = (vc_data.font.width + 7) / 8; 621 let cellsize = width * vc_data.font.height; 622 let fb_info = self.fb(); 623 // 一次能输出的最大字数,避免帧缓冲区溢出 624 let max_cnt = (fb_info.current_fb_var().xres * fb_info.current_fb_var().yres) / cellsize; 625 let attr = FbConAttr::get_attr(data[0], fb_info.color_depth()); 626 627 let mut image = FbImage { 628 x: x * vc_data.font.width, 629 y: y * vc_data.font.height, 630 width: 0, 631 height: vc_data.font.height, 632 fg, 633 bg, 634 depth: 1, 635 data: Default::default(), 636 }; 637 638 image.data.resize(cellsize as usize * count as usize, 0); 639 640 while count > 0 { 641 let cnt = count.min(max_cnt); 642 643 image.width = vc_data.font.width * cnt; 644 645 self.bit_put_string(vc_data, data, attr, cnt, cellsize, &mut image); 646 647 image.x += cnt * vc_data.font.width; 648 count -= cnt; 649 } 650 651 Ok(()) 652 } 653 654 fn fbcon_data(&self) -> SpinLockGuard<super::FrameBufferConsoleData> { 655 self.fbcon_data.lock() 656 } 657 658 fn cursor(&self, vc_data: &VirtualConsoleData, op: CursorOperation, fg: u32, bg: u32) { 659 let mut fbcon_data = self.fbcon_data(); 660 let fb_info = self.fb(); 661 let mut cursor = FbCursor::default(); 662 let charmask = if vc_data.hi_font_mask != 0 { 663 0x1ff 664 } else { 665 0xff 666 }; 667 668 // 向上取整 669 let w = (vc_data.font.width + 7) / 8; 670 let y = fbcon_data.display.real_y(vc_data.state.y as u32); 671 672 let c = vc_data.screen_buf[vc_data.pos]; 673 let attr = FbConAttr::get_attr(c, fb_info.color_depth()); 674 let char_offset = (c as usize & charmask) * ((w * vc_data.font.height) as usize); 675 676 if fbcon_data.cursor_state.image.data != vc_data.font.data[char_offset..] 677 || fbcon_data.cursor_reset 678 { 679 fbcon_data.cursor_state.image.data = vc_data.font.data[char_offset..].to_vec(); 680 cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETIMAGE); 681 } 682 683 if !attr.is_empty() { 684 fbcon_data 685 .cursor_data 686 .resize(w as usize * vc_data.font.height as usize, 0); 687 688 attr.update_attr( 689 &mut fbcon_data.cursor_data, 690 &vc_data.font.data[char_offset..], 691 vc_data, 692 ); 693 } 694 695 if fbcon_data.cursor_state.image.fg != fg 696 || fbcon_data.cursor_state.image.bg != bg 697 || fbcon_data.cursor_reset 698 { 699 fbcon_data.cursor_state.image.fg = fg; 700 fbcon_data.cursor_state.image.bg = bg; 701 cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETCMAP); 702 } 703 704 if fbcon_data.cursor_state.image.x != (vc_data.font.width * vc_data.state.x as u32) 705 || fbcon_data.cursor_state.image.y != (vc_data.font.height * y) 706 || fbcon_data.cursor_reset 707 { 708 fbcon_data.cursor_state.image.x = vc_data.font.width * vc_data.state.x as u32; 709 fbcon_data.cursor_state.image.y = vc_data.font.height * y; 710 cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETPOS); 711 } 712 713 if fbcon_data.cursor_state.image.height != vc_data.font.height 714 || fbcon_data.cursor_state.image.width != vc_data.font.width 715 || fbcon_data.cursor_reset 716 { 717 fbcon_data.cursor_state.image.height = vc_data.font.height; 718 fbcon_data.cursor_state.image.width = vc_data.font.width; 719 cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSIZE); 720 } 721 722 if fbcon_data.cursor_state.hot_x > 0 723 || fbcon_data.cursor_state.hot_y > 0 724 || fbcon_data.cursor_reset 725 { 726 fbcon_data.cursor_state.hot_x = 0; 727 cursor.hot_y = 0; 728 cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETHOT); 729 } 730 731 if cursor.set_mode.contains(FbCursorSetMode::FB_CUR_SETSIZE) 732 || vc_data.cursor_type != fbcon_data.display.cursor_shape 733 || fbcon_data.cursor_state.mask.is_empty() 734 || fbcon_data.cursor_reset 735 { 736 fbcon_data.display.cursor_shape = vc_data.cursor_type; 737 cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSHAPE); 738 739 let cur_height; 740 match fbcon_data.display.cursor_shape.cursor_size() { 741 VcCursor::CUR_NONE => { 742 cur_height = 0; 743 } 744 VcCursor::CUR_UNDERLINE => { 745 if vc_data.font.height < 10 { 746 cur_height = 1; 747 } else { 748 cur_height = 2; 749 } 750 } 751 VcCursor::CUR_LOWER_THIRD => { 752 cur_height = vc_data.font.height / 3; 753 } 754 VcCursor::CUR_LOWER_HALF => { 755 cur_height = vc_data.font.height >> 1; 756 } 757 VcCursor::CUR_TWO_THIRDS => { 758 cur_height = (vc_data.font.height << 1) / 3; 759 } 760 _ => { 761 cur_height = vc_data.font.height; 762 } 763 } 764 765 // 表示空白部分 766 let mut size = (vc_data.font.height - cur_height) * w; 767 while size > 0 { 768 size -= 1; 769 fbcon_data.cursor_state.mask.push(0x00); 770 } 771 size = cur_height * w; 772 // 表示光标显示部分 773 while size > 0 { 774 size -= 1; 775 fbcon_data.cursor_state.mask.push(0xff); 776 } 777 } 778 779 match op { 780 CursorOperation::Erase => { 781 fbcon_data.cursor_state.enable = false; 782 } 783 _ => { 784 fbcon_data.cursor_state.enable = !vc_data.cursor_type.contains(VcCursor::CUR_SW); 785 } 786 } 787 788 if !attr.is_empty() { 789 cursor.image.data = fbcon_data.cursor_data.clone(); 790 } else { 791 cursor.image.data = vc_data.font.data 792 [char_offset..char_offset + (w as usize * vc_data.font.height as usize)] 793 .to_vec(); 794 } 795 cursor.image.fg = fbcon_data.cursor_state.image.fg; 796 cursor.image.bg = fbcon_data.cursor_state.image.bg; 797 cursor.image.x = fbcon_data.cursor_state.image.x; 798 cursor.image.y = fbcon_data.cursor_state.image.y; 799 cursor.image.height = fbcon_data.cursor_state.image.height; 800 cursor.image.width = fbcon_data.cursor_state.image.width; 801 cursor.hot_x = fbcon_data.cursor_state.hot_x; 802 cursor.hot_y = fbcon_data.cursor_state.hot_y; 803 cursor.mask = fbcon_data.cursor_state.mask.clone(); 804 cursor.enable = fbcon_data.cursor_state.enable; 805 cursor.image.depth = 1; 806 cursor.rop = true; 807 808 if fb_info.fb_cursor(&cursor).is_err() { 809 let _ = fb_info.soft_cursor(cursor); 810 } 811 812 fbcon_data.cursor_reset = false; 813 } 814 } 815