mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-25 18:23:22 +00:00
完成与Linux兼容的Ntty (#517)
* 已经完成的功能: - 写:printf能够正常在tty输出 - 读:与键盘驱动接上 - 信号: 能够正常通过ctrl向前台进程发送信号 * 支持目前的shell,改动printk使其与新版tty兼容。 * 删除原有tty文件夹,并更改新tty文件名 * 添加clear清屏程序 * 实现tty部分ioctl,更改部分问题
This commit is contained in:
1
kernel/src/driver/video/fbdev/base/fbcmap.rs
Normal file
1
kernel/src/driver/video/fbdev/base/fbcmap.rs
Normal file
@ -0,0 +1 @@
|
||||
|
787
kernel/src/driver/video/fbdev/base/fbcon/framebuffer_console.rs
Normal file
787
kernel/src/driver/video/fbdev/base/fbcon/framebuffer_console.rs
Normal file
@ -0,0 +1,787 @@
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
driver::{
|
||||
tty::{
|
||||
console::ConsoleSwitch,
|
||||
virtual_terminal::{
|
||||
virtual_console::{CursorOperation, ScrollDir, VcCursor, VirtualConsoleData},
|
||||
Color,
|
||||
},
|
||||
},
|
||||
video::fbdev::base::{
|
||||
CopyAreaData, FbCursor, FbCursorSetMode, FbImage, FbVisual, FillRectData, FillRectROP,
|
||||
FrameBuffer, ScrollMode, FRAME_BUFFER_SET,
|
||||
},
|
||||
},
|
||||
libs::{
|
||||
font::FontDesc,
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
},
|
||||
};
|
||||
|
||||
use super::{FbConAttr, FrameBufferConsole, FrameBufferConsoleData};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BlittingFbConsole {
|
||||
fb: SpinLock<Option<Arc<dyn FrameBuffer>>>,
|
||||
fbcon_data: SpinLock<FrameBufferConsoleData>,
|
||||
}
|
||||
|
||||
unsafe impl Send for BlittingFbConsole {}
|
||||
unsafe impl Sync for BlittingFbConsole {}
|
||||
|
||||
impl BlittingFbConsole {
|
||||
pub fn new() -> Result<Self, SystemError> {
|
||||
Ok(Self {
|
||||
fb: SpinLock::new(None),
|
||||
fbcon_data: SpinLock::new(FrameBufferConsoleData::default()),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn fb(&self) -> Arc<dyn FrameBuffer> {
|
||||
self.fb.lock().clone().unwrap()
|
||||
}
|
||||
|
||||
pub fn get_color(&self, vc_data: &VirtualConsoleData, c: u16, is_fg: bool) -> u32 {
|
||||
let fb_info = self.fb();
|
||||
let mut color = 0;
|
||||
|
||||
let depth = fb_info.color_depth();
|
||||
|
||||
if depth != 1 {
|
||||
if is_fg {
|
||||
let fg_shift = if vc_data.hi_font_mask != 0 { 9 } else { 8 };
|
||||
color = (c as u32 >> fg_shift) & 0x0f
|
||||
} else {
|
||||
let bg_shift = if vc_data.hi_font_mask != 0 { 13 } else { 12 };
|
||||
color = (c as u32 >> bg_shift) & 0x0f
|
||||
}
|
||||
}
|
||||
|
||||
match depth {
|
||||
1 => {
|
||||
let col = self.mono_color();
|
||||
let fg;
|
||||
let bg;
|
||||
if fb_info.current_fb_fix().visual != FbVisual::Mono01 {
|
||||
fg = col;
|
||||
bg = 0;
|
||||
} else {
|
||||
fg = 0;
|
||||
bg = col;
|
||||
}
|
||||
color = if is_fg { fg } else { bg };
|
||||
}
|
||||
2 => {
|
||||
/*
|
||||
颜色深度为2,即16色,
|
||||
将16色的颜色值映射到4色的灰度,
|
||||
其中颜色0映射为黑色,颜色1到6映射为白色,
|
||||
颜色7到8映射为灰色,其他颜色映射为强烈的白色。
|
||||
*/
|
||||
if color >= 1 && color <= 6 {
|
||||
// 白色
|
||||
color = 2;
|
||||
} else if color >= 7 && color <= 8 {
|
||||
// 灰色
|
||||
color = 1;
|
||||
} else {
|
||||
// 强白
|
||||
color = 3;
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
/*
|
||||
颜色深度为3,即256色,仅保留颜色的低3位,即颜色 0 到 7
|
||||
*/
|
||||
color &= 7;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
color
|
||||
}
|
||||
|
||||
/// ## 计算单色调的函数
|
||||
pub fn mono_color(&self) -> u32 {
|
||||
let fb_info = self.fb();
|
||||
let mut max_len = fb_info
|
||||
.current_fb_var()
|
||||
.green
|
||||
.length
|
||||
.max(fb_info.current_fb_var().red.length);
|
||||
|
||||
max_len = max_len.max(fb_info.current_fb_var().blue.length);
|
||||
|
||||
return (!(0xfff << max_len)) & 0xff;
|
||||
}
|
||||
|
||||
pub fn bit_put_string(
|
||||
&self,
|
||||
vc_data: &VirtualConsoleData,
|
||||
buf: &[u16],
|
||||
attr: FbConAttr,
|
||||
cnt: u32,
|
||||
cellsize: u32,
|
||||
image: &mut FbImage,
|
||||
) {
|
||||
let charmask = if vc_data.hi_font_mask != 0 {
|
||||
0x1ff
|
||||
} else {
|
||||
0xff
|
||||
};
|
||||
|
||||
let mut offset;
|
||||
let image_line_byte = image.width as usize / 8;
|
||||
|
||||
let byte_width = vc_data.font.width as usize / 8;
|
||||
let font_height = vc_data.font.height as usize;
|
||||
// let mut char_offset = 0;
|
||||
for char_offset in 0..cnt as usize {
|
||||
// 在字符表中的index
|
||||
let ch = buf[char_offset] & charmask;
|
||||
// 计算出在font表中的偏移量
|
||||
let font_offset = ch as usize * cellsize as usize;
|
||||
let font_offset_end = font_offset + cellsize as usize;
|
||||
// 设置image的data
|
||||
|
||||
let src = &vc_data.font.data[font_offset..font_offset_end];
|
||||
let mut dst = Vec::new();
|
||||
dst.resize(src.len(), 0);
|
||||
dst.copy_from_slice(src);
|
||||
|
||||
if !attr.is_empty() {
|
||||
attr.update_attr(&mut dst, src, vc_data)
|
||||
}
|
||||
|
||||
offset = char_offset * byte_width;
|
||||
let mut dst_offset = 0;
|
||||
for _ in 0..font_height {
|
||||
let dst_offset_next = dst_offset + byte_width;
|
||||
image.data[offset..offset + byte_width]
|
||||
.copy_from_slice(&dst[dst_offset..dst_offset_next]);
|
||||
|
||||
offset += image_line_byte;
|
||||
dst_offset = dst_offset_next;
|
||||
}
|
||||
}
|
||||
|
||||
self.fb().fb_image_blit(image);
|
||||
}
|
||||
}
|
||||
|
||||
impl ConsoleSwitch for BlittingFbConsole {
|
||||
fn con_init(
|
||||
&self,
|
||||
vc_data: &mut VirtualConsoleData,
|
||||
init: bool,
|
||||
) -> Result<(), system_error::SystemError> {
|
||||
let fb_set_guard = FRAME_BUFFER_SET.read();
|
||||
let fb = fb_set_guard.get(vc_data.index);
|
||||
if fb.is_none() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
let fb = fb.unwrap();
|
||||
if fb.is_none() {
|
||||
panic!(
|
||||
"The Framebuffer with FbID {} has not been initialized yet.",
|
||||
vc_data.index
|
||||
)
|
||||
}
|
||||
|
||||
let fb = fb.as_ref().unwrap().clone();
|
||||
|
||||
if init {
|
||||
// 初始化字体
|
||||
let var = fb.current_fb_var();
|
||||
let font = FontDesc::get_default_font(var.xres, var.yres, 0, 0);
|
||||
vc_data.font.data = font.data.to_vec();
|
||||
vc_data.font.width = font.width;
|
||||
vc_data.font.height = font.height;
|
||||
vc_data.font.count = font.char_count;
|
||||
} else {
|
||||
kwarn!("The frontend Framebuffer is not implemented");
|
||||
}
|
||||
|
||||
vc_data.color_mode = fb.color_depth() != 1;
|
||||
vc_data.complement_mask = if vc_data.color_mode { 0x7700 } else { 0x0800 };
|
||||
|
||||
if vc_data.font.count == 256 {
|
||||
// ascii
|
||||
vc_data.hi_font_mask = 0;
|
||||
} else {
|
||||
vc_data.hi_font_mask = 0x100;
|
||||
if vc_data.color_mode {
|
||||
vc_data.complement_mask <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 考虑rotate
|
||||
if init {
|
||||
vc_data.cols = (fb.current_fb_var().xres / vc_data.font.width) as usize;
|
||||
vc_data.rows = (fb.current_fb_var().yres / vc_data.font.height) as usize;
|
||||
|
||||
vc_data.pos = vc_data.state.x + vc_data.state.y * vc_data.cols;
|
||||
|
||||
let new_size = vc_data.cols * vc_data.rows;
|
||||
vc_data.screen_buf.resize(new_size, 0);
|
||||
} else {
|
||||
unimplemented!("Resize is not supported at the moment!");
|
||||
}
|
||||
|
||||
// 初始化fb
|
||||
*self.fb.lock() = Some(fb);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn con_deinit(&self) -> Result<(), system_error::SystemError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn con_clear(
|
||||
&self,
|
||||
vc_data: &mut VirtualConsoleData,
|
||||
sy: usize,
|
||||
sx: usize,
|
||||
height: usize,
|
||||
width: usize,
|
||||
) -> Result<(), system_error::SystemError> {
|
||||
let fb_data = self.fbcon_data();
|
||||
|
||||
if height == 0 || width == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let y_break = (fb_data.display.virt_rows - fb_data.display.yscroll) as usize;
|
||||
if sy < y_break && sy + height - 1 >= y_break {
|
||||
// 分两次clear
|
||||
let b = y_break - sy;
|
||||
let _ = self.clear(
|
||||
&vc_data,
|
||||
fb_data.display.real_y(sy as u32),
|
||||
sx as u32,
|
||||
b as u32,
|
||||
width as u32,
|
||||
);
|
||||
let _ = self.clear(
|
||||
&vc_data,
|
||||
fb_data.display.real_y((sy + b) as u32),
|
||||
sx as u32,
|
||||
(height - b) as u32,
|
||||
width as u32,
|
||||
);
|
||||
} else {
|
||||
let _ = self.clear(
|
||||
&vc_data,
|
||||
fb_data.display.real_y(sy as u32),
|
||||
sx as u32,
|
||||
height as u32,
|
||||
width as u32,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn con_putc(
|
||||
&self,
|
||||
vc_data: &VirtualConsoleData,
|
||||
ch: u16,
|
||||
xpos: u32,
|
||||
ypos: u32,
|
||||
) -> Result<(), system_error::SystemError> {
|
||||
self.con_putcs(vc_data, &[ch], 1, ypos, xpos)
|
||||
}
|
||||
|
||||
fn con_putcs(
|
||||
&self,
|
||||
vc_data: &VirtualConsoleData,
|
||||
buf: &[u16],
|
||||
count: usize,
|
||||
ypos: u32,
|
||||
xpos: u32,
|
||||
) -> Result<(), SystemError> {
|
||||
if count == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
let fbcon_data = self.fbcon_data();
|
||||
let c = buf[0];
|
||||
self.put_string(
|
||||
vc_data,
|
||||
buf,
|
||||
count as u32,
|
||||
fbcon_data.display.real_y(ypos),
|
||||
xpos,
|
||||
self.get_color(vc_data, c, true),
|
||||
self.get_color(vc_data, c, false),
|
||||
)
|
||||
}
|
||||
|
||||
fn con_getxy(
|
||||
&self,
|
||||
vc_data: &VirtualConsoleData,
|
||||
pos: usize,
|
||||
) -> Result<(usize, usize, usize), SystemError> {
|
||||
if pos < vc_data.screen_buf.len() {
|
||||
let x = pos % vc_data.cols;
|
||||
let y = pos / vc_data.cols;
|
||||
let mut next_line_start = pos + (vc_data.cols - x);
|
||||
if next_line_start >= vc_data.screen_buf.len() {
|
||||
next_line_start = 0
|
||||
}
|
||||
return Ok((next_line_start, x, y));
|
||||
} else {
|
||||
return Ok((0, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
fn con_cursor(
|
||||
&self,
|
||||
vc_data: &VirtualConsoleData,
|
||||
op: crate::driver::tty::virtual_terminal::virtual_console::CursorOperation,
|
||||
) {
|
||||
let mut fbcon_data = self.fbcon_data();
|
||||
|
||||
let c = vc_data.screen_buf[vc_data.pos];
|
||||
|
||||
if vc_data.cursor_type.contains(VcCursor::CUR_SW) {
|
||||
// 取消硬光标Timer,但是现在没有硬光标,先写在这
|
||||
} else {
|
||||
// 添加硬光标Timer
|
||||
}
|
||||
|
||||
fbcon_data.cursor_flash = op != CursorOperation::Erase;
|
||||
|
||||
drop(fbcon_data);
|
||||
|
||||
self.cursor(
|
||||
vc_data,
|
||||
op,
|
||||
self.get_color(vc_data, c, true),
|
||||
self.get_color(vc_data, c, false),
|
||||
);
|
||||
}
|
||||
|
||||
fn con_set_palette(
|
||||
&self,
|
||||
vc_data: &VirtualConsoleData,
|
||||
color_table: &[u8],
|
||||
) -> Result<(), SystemError> {
|
||||
let fb_info = self.fb();
|
||||
let depth = fb_info.color_depth();
|
||||
let mut palette = Vec::new();
|
||||
palette.resize(16, Color::default());
|
||||
if depth > 3 {
|
||||
let vc_palette = &vc_data.palette;
|
||||
for i in 0..16 {
|
||||
let idx = color_table[i];
|
||||
let col = palette.get_mut(idx as usize).unwrap();
|
||||
col.red = (vc_palette[i].red << 8) | vc_palette[i].red;
|
||||
col.green = (vc_palette[i].green << 8) | vc_palette[i].green;
|
||||
col.blue = (vc_palette[i].blue << 8) | vc_palette[i].blue;
|
||||
}
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
|
||||
self.fb().set_color_map(palette)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn con_scroll(
|
||||
&self,
|
||||
vc_data: &mut VirtualConsoleData,
|
||||
top: usize,
|
||||
bottom: usize,
|
||||
dir: crate::driver::tty::virtual_terminal::virtual_console::ScrollDir,
|
||||
mut count: usize,
|
||||
) -> bool {
|
||||
self.con_cursor(vc_data, CursorOperation::Erase);
|
||||
|
||||
let fbcon_data = self.fbcon_data();
|
||||
let scroll_mode = fbcon_data.display.scroll_mode;
|
||||
|
||||
drop(fbcon_data);
|
||||
|
||||
match dir {
|
||||
ScrollDir::Up => {
|
||||
if count > vc_data.rows {
|
||||
count = vc_data.rows;
|
||||
}
|
||||
|
||||
match scroll_mode {
|
||||
ScrollMode::Move => {
|
||||
let start = top * vc_data.cols;
|
||||
let end = bottom * vc_data.cols;
|
||||
vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols);
|
||||
|
||||
let _ = self.bmove(
|
||||
vc_data,
|
||||
top as i32,
|
||||
0,
|
||||
top as i32 - count as i32,
|
||||
0,
|
||||
(bottom - top) as u32,
|
||||
vc_data.cols as u32,
|
||||
);
|
||||
|
||||
let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols);
|
||||
|
||||
let offset = vc_data.cols * (bottom - count);
|
||||
for i in
|
||||
vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
|
||||
{
|
||||
*i = vc_data.erase_char;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
ScrollMode::PanMove => todo!(),
|
||||
ScrollMode::WrapMove => todo!(),
|
||||
ScrollMode::Redraw => {
|
||||
let start = top * vc_data.cols;
|
||||
let end = bottom * vc_data.cols;
|
||||
vc_data.screen_buf[start..end].rotate_left(count * vc_data.cols);
|
||||
|
||||
let data = &vc_data.screen_buf[start..(bottom - count) * vc_data.cols];
|
||||
|
||||
for line in top..(bottom - count) {
|
||||
let mut start = line * vc_data.cols;
|
||||
let end = start + vc_data.cols;
|
||||
let mut offset = start;
|
||||
let mut attr = 1;
|
||||
let mut x = 0;
|
||||
while offset < end {
|
||||
let c = data[offset];
|
||||
|
||||
if attr != c & 0xff00 {
|
||||
// 属性变化,输出完上一个的并且更新属性
|
||||
attr = c & 0xff00;
|
||||
|
||||
let count = offset - start;
|
||||
let _ = self.con_putcs(
|
||||
vc_data,
|
||||
&data[start..offset],
|
||||
count,
|
||||
line as u32,
|
||||
x,
|
||||
);
|
||||
start = offset;
|
||||
x += count as u32;
|
||||
}
|
||||
|
||||
offset += 1;
|
||||
}
|
||||
let _ = self.con_putcs(
|
||||
vc_data,
|
||||
&data[start..offset],
|
||||
offset - start,
|
||||
line as u32,
|
||||
x,
|
||||
);
|
||||
}
|
||||
|
||||
let _ = self.con_clear(vc_data, bottom - count, 0, count, vc_data.cols);
|
||||
|
||||
let offset = vc_data.cols * (bottom - count);
|
||||
for i in
|
||||
vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
|
||||
{
|
||||
*i = vc_data.erase_char;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
ScrollMode::PanRedraw => todo!(),
|
||||
}
|
||||
}
|
||||
ScrollDir::Down => {
|
||||
if count > vc_data.rows {
|
||||
count = vc_data.rows;
|
||||
}
|
||||
|
||||
match scroll_mode {
|
||||
ScrollMode::Move => todo!(),
|
||||
ScrollMode::PanMove => todo!(),
|
||||
ScrollMode::WrapMove => todo!(),
|
||||
ScrollMode::Redraw => {
|
||||
// self.scroll_redraw(
|
||||
// vc_data,
|
||||
// bottom - 1,
|
||||
// bottom - top - count,
|
||||
// count * vc_data.cols,
|
||||
// false,
|
||||
// );
|
||||
|
||||
let _ = self.con_clear(vc_data, top, 0, count, vc_data.cols);
|
||||
|
||||
let offset = vc_data.cols * top;
|
||||
for i in
|
||||
vc_data.screen_buf[offset..(offset + (vc_data.cols * count))].iter_mut()
|
||||
{
|
||||
*i = vc_data.erase_char;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
ScrollMode::PanRedraw => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FrameBufferConsole for BlittingFbConsole {
|
||||
fn bmove(
|
||||
&self,
|
||||
vc_data: &VirtualConsoleData,
|
||||
sy: i32,
|
||||
sx: i32,
|
||||
dy: i32,
|
||||
dx: i32,
|
||||
height: u32,
|
||||
width: u32,
|
||||
) -> Result<(), SystemError> {
|
||||
let area = CopyAreaData::new(
|
||||
dx * vc_data.font.width as i32,
|
||||
dy * vc_data.font.height as i32,
|
||||
width * vc_data.font.width,
|
||||
height * vc_data.font.height,
|
||||
sx * vc_data.font.width as i32,
|
||||
sy * vc_data.font.height as i32,
|
||||
);
|
||||
|
||||
self.fb().fb_copyarea(area)
|
||||
}
|
||||
|
||||
fn clear(
|
||||
&self,
|
||||
vc_data: &VirtualConsoleData,
|
||||
sy: u32,
|
||||
sx: u32,
|
||||
height: u32,
|
||||
width: u32,
|
||||
) -> Result<(), SystemError> {
|
||||
let region = FillRectData::new(
|
||||
sx * vc_data.font.width,
|
||||
sy * vc_data.font.height,
|
||||
width * vc_data.font.width,
|
||||
height * vc_data.font.height,
|
||||
self.get_color(vc_data, vc_data.erase_char, false),
|
||||
FillRectROP::Copy,
|
||||
);
|
||||
|
||||
self.fb().fb_fillrect(region)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn put_string(
|
||||
&self,
|
||||
vc_data: &VirtualConsoleData,
|
||||
data: &[u16],
|
||||
mut count: u32,
|
||||
y: u32,
|
||||
x: u32,
|
||||
fg: u32,
|
||||
bg: u32,
|
||||
) -> Result<(), SystemError> {
|
||||
// 向上取整
|
||||
let width = (vc_data.font.width + 7) / 8;
|
||||
let cellsize = width * vc_data.font.height;
|
||||
let fb_info = self.fb();
|
||||
// 一次能输出的最大字数,避免帧缓冲区溢出
|
||||
let max_cnt = (fb_info.current_fb_var().xres * fb_info.current_fb_var().yres) / cellsize;
|
||||
let attr = FbConAttr::get_attr(data[0], fb_info.color_depth());
|
||||
|
||||
let mut image = FbImage {
|
||||
x: x * vc_data.font.width,
|
||||
y: y * vc_data.font.height,
|
||||
width: 0,
|
||||
height: vc_data.font.height,
|
||||
fg,
|
||||
bg,
|
||||
depth: 1,
|
||||
data: Default::default(),
|
||||
};
|
||||
|
||||
image.data.resize(cellsize as usize * count as usize, 0);
|
||||
|
||||
while count > 0 {
|
||||
let cnt = count.min(max_cnt);
|
||||
|
||||
image.width = vc_data.font.width * cnt;
|
||||
|
||||
self.bit_put_string(vc_data, data, attr, cnt, cellsize, &mut image);
|
||||
|
||||
image.x += cnt * vc_data.font.width;
|
||||
count -= cnt;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fbcon_data(&self) -> SpinLockGuard<super::FrameBufferConsoleData> {
|
||||
self.fbcon_data.lock()
|
||||
}
|
||||
|
||||
fn cursor(&self, vc_data: &VirtualConsoleData, op: CursorOperation, fg: u32, bg: u32) {
|
||||
let mut fbcon_data = self.fbcon_data();
|
||||
let fb_info = self.fb();
|
||||
let mut cursor = FbCursor::default();
|
||||
let charmask = if vc_data.hi_font_mask != 0 {
|
||||
0x1ff
|
||||
} else {
|
||||
0xff
|
||||
};
|
||||
|
||||
// 向上取整
|
||||
let w = (vc_data.font.width + 7) / 8;
|
||||
let y = fbcon_data.display.real_y(vc_data.state.y as u32);
|
||||
|
||||
let c = vc_data.screen_buf[vc_data.pos];
|
||||
let attr = FbConAttr::get_attr(c, fb_info.color_depth());
|
||||
let char_offset = (c as usize & charmask) * ((w * vc_data.font.height) as usize);
|
||||
|
||||
if fbcon_data.cursor_state.image.data != &vc_data.font.data[char_offset..]
|
||||
|| fbcon_data.cursor_reset
|
||||
{
|
||||
fbcon_data.cursor_state.image.data = vc_data.font.data[char_offset..].to_vec();
|
||||
cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETIMAGE);
|
||||
}
|
||||
|
||||
if !attr.is_empty() {
|
||||
fbcon_data
|
||||
.cursor_data
|
||||
.resize(w as usize * vc_data.font.height as usize, 0);
|
||||
|
||||
attr.update_attr(
|
||||
&mut fbcon_data.cursor_data,
|
||||
&vc_data.font.data[char_offset..],
|
||||
vc_data,
|
||||
);
|
||||
}
|
||||
|
||||
if fbcon_data.cursor_state.image.fg != fg
|
||||
|| fbcon_data.cursor_state.image.bg != bg
|
||||
|| fbcon_data.cursor_reset
|
||||
{
|
||||
fbcon_data.cursor_state.image.fg = fg;
|
||||
fbcon_data.cursor_state.image.bg = bg;
|
||||
cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETCMAP);
|
||||
}
|
||||
|
||||
if fbcon_data.cursor_state.image.x != (vc_data.font.width * vc_data.state.x as u32)
|
||||
|| fbcon_data.cursor_state.image.y != (vc_data.font.height * y)
|
||||
|| fbcon_data.cursor_reset
|
||||
{
|
||||
fbcon_data.cursor_state.image.x = vc_data.font.width * vc_data.state.x as u32;
|
||||
fbcon_data.cursor_state.image.y = vc_data.font.height * y;
|
||||
cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETPOS);
|
||||
}
|
||||
|
||||
if fbcon_data.cursor_state.image.height != vc_data.font.height
|
||||
|| fbcon_data.cursor_state.image.width != vc_data.font.width
|
||||
|| fbcon_data.cursor_reset
|
||||
{
|
||||
fbcon_data.cursor_state.image.height = vc_data.font.height;
|
||||
fbcon_data.cursor_state.image.width = vc_data.font.width;
|
||||
cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSIZE);
|
||||
}
|
||||
|
||||
if fbcon_data.cursor_state.hot_x > 0
|
||||
|| fbcon_data.cursor_state.hot_y > 0
|
||||
|| fbcon_data.cursor_reset
|
||||
{
|
||||
fbcon_data.cursor_state.hot_x = 0;
|
||||
cursor.hot_y = 0;
|
||||
cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETHOT);
|
||||
}
|
||||
|
||||
if cursor.set_mode.contains(FbCursorSetMode::FB_CUR_SETSIZE)
|
||||
|| vc_data.cursor_type != fbcon_data.display.cursor_shape
|
||||
|| fbcon_data.cursor_state.mask.is_empty()
|
||||
|| fbcon_data.cursor_reset
|
||||
{
|
||||
fbcon_data.display.cursor_shape = vc_data.cursor_type;
|
||||
cursor.set_mode.insert(FbCursorSetMode::FB_CUR_SETSHAPE);
|
||||
|
||||
let cur_height;
|
||||
match fbcon_data.display.cursor_shape.cursor_size() {
|
||||
VcCursor::CUR_NONE => {
|
||||
cur_height = 0;
|
||||
}
|
||||
VcCursor::CUR_UNDERLINE => {
|
||||
if vc_data.font.height < 10 {
|
||||
cur_height = 1;
|
||||
} else {
|
||||
cur_height = 2;
|
||||
}
|
||||
}
|
||||
VcCursor::CUR_LOWER_THIRD => {
|
||||
cur_height = vc_data.font.height / 3;
|
||||
}
|
||||
VcCursor::CUR_LOWER_HALF => {
|
||||
cur_height = vc_data.font.height >> 1;
|
||||
}
|
||||
VcCursor::CUR_TWO_THIRDS => {
|
||||
cur_height = (vc_data.font.height << 1) / 3;
|
||||
}
|
||||
_ => {
|
||||
cur_height = vc_data.font.height;
|
||||
}
|
||||
}
|
||||
|
||||
// 表示空白部分
|
||||
let mut size = (vc_data.font.height - cur_height) * w;
|
||||
while size > 0 {
|
||||
size -= 1;
|
||||
fbcon_data.cursor_state.mask.push(0x00);
|
||||
}
|
||||
size = cur_height * w;
|
||||
// 表示光标显示部分
|
||||
while size > 0 {
|
||||
size -= 1;
|
||||
fbcon_data.cursor_state.mask.push(0xff);
|
||||
}
|
||||
}
|
||||
|
||||
match op {
|
||||
CursorOperation::Erase => {
|
||||
fbcon_data.cursor_state.enable = false;
|
||||
}
|
||||
_ => {
|
||||
fbcon_data.cursor_state.enable = !vc_data.cursor_type.contains(VcCursor::CUR_SW);
|
||||
}
|
||||
}
|
||||
|
||||
if !attr.is_empty() {
|
||||
cursor.image.data = fbcon_data.cursor_data.clone();
|
||||
} else {
|
||||
cursor.image.data = vc_data.font.data
|
||||
[char_offset..char_offset + (w as usize * vc_data.font.height as usize)]
|
||||
.to_vec();
|
||||
}
|
||||
cursor.image.fg = fbcon_data.cursor_state.image.fg;
|
||||
cursor.image.bg = fbcon_data.cursor_state.image.bg;
|
||||
cursor.image.x = fbcon_data.cursor_state.image.x;
|
||||
cursor.image.y = fbcon_data.cursor_state.image.y;
|
||||
cursor.image.height = fbcon_data.cursor_state.image.height;
|
||||
cursor.image.width = fbcon_data.cursor_state.image.width;
|
||||
cursor.hot_x = fbcon_data.cursor_state.hot_x;
|
||||
cursor.hot_y = fbcon_data.cursor_state.hot_y;
|
||||
cursor.mask = fbcon_data.cursor_state.mask.clone();
|
||||
cursor.enable = fbcon_data.cursor_state.enable;
|
||||
cursor.image.depth = 1;
|
||||
cursor.rop = true;
|
||||
|
||||
if fb_info.fb_cursor(&cursor).is_err() {
|
||||
let _ = fb_info.soft_cursor(cursor);
|
||||
}
|
||||
|
||||
fbcon_data.cursor_reset = false;
|
||||
}
|
||||
}
|
@ -1,15 +1,19 @@
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
driver::base::{
|
||||
class::Class,
|
||||
device::{bus::Bus, device_manager, driver::Driver, Device, DeviceType, IdTable},
|
||||
kobject::{KObjType, KObject, KObjectState, LockedKObjectState},
|
||||
kset::KSet,
|
||||
driver::{
|
||||
base::{
|
||||
class::Class,
|
||||
device::{bus::Bus, device_manager, driver::Driver, Device, DeviceType, IdTable},
|
||||
kobject::{KObjType, KObject, KObjectState, LockedKObjectState},
|
||||
kset::KSet,
|
||||
},
|
||||
tty::virtual_terminal::virtual_console::{CursorOperation, VcCursor, VirtualConsoleData},
|
||||
},
|
||||
filesystem::{
|
||||
kernfs::KernFSInode,
|
||||
@ -18,11 +22,13 @@ use crate::{
|
||||
},
|
||||
libs::{
|
||||
rwlock::{RwLockReadGuard, RwLockWriteGuard},
|
||||
spinlock::SpinLock,
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
},
|
||||
};
|
||||
|
||||
use super::fbmem::sys_class_graphics_instance;
|
||||
use super::{fbmem::sys_class_graphics_instance, FbCursor, ScrollMode};
|
||||
|
||||
pub mod framebuffer_console;
|
||||
|
||||
/// framebuffer console设备管理器实例
|
||||
static mut FB_CONSOLE_MANAGER: Option<FbConsoleManager> = None;
|
||||
@ -332,3 +338,166 @@ impl Attribute for AttrCursorBlink {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct FrameBufferConsoleData {
|
||||
/// 光标闪烁间隔
|
||||
pub cursor_blink_jiffies: i64,
|
||||
/// 是否刷新光标
|
||||
pub cursor_flash: bool,
|
||||
///
|
||||
pub display: FbConsoleDisplay,
|
||||
/// 光标状态
|
||||
pub cursor_state: FbCursor,
|
||||
/// 重设光标?
|
||||
pub cursor_reset: bool,
|
||||
/// cursor 位图数据
|
||||
pub cursor_data: Vec<u8>,
|
||||
}
|
||||
|
||||
pub trait FrameBufferConsole {
|
||||
fn fbcon_data(&self) -> SpinLockGuard<FrameBufferConsoleData>;
|
||||
|
||||
/// ## 将位块移动到目标位置
|
||||
/// 坐标均以字体为单位而不是pixel
|
||||
/// ### 参数
|
||||
/// ### sy: 起始位置的y坐标
|
||||
/// ### sx: 起始位置的x坐标、
|
||||
/// ### dy: 目标位置的y坐标
|
||||
/// ### dx: 目标位置的x坐标
|
||||
/// ### height: 位图高度
|
||||
/// ### width: 位图宽度
|
||||
fn bmove(
|
||||
&self,
|
||||
vc_data: &VirtualConsoleData,
|
||||
sy: i32,
|
||||
sx: i32,
|
||||
dy: i32,
|
||||
dx: i32,
|
||||
height: u32,
|
||||
width: u32,
|
||||
) -> Result<(), SystemError>;
|
||||
|
||||
/// ## 清除位图
|
||||
///
|
||||
/// ### 参数
|
||||
/// ### sy: 原位置的y坐标
|
||||
/// ### sx: 原位置的x坐标、
|
||||
/// ### height: 位图高度
|
||||
/// ### width: 位图宽度
|
||||
fn clear(
|
||||
&self,
|
||||
vc_data: &VirtualConsoleData,
|
||||
sy: u32,
|
||||
sx: u32,
|
||||
height: u32,
|
||||
width: u32,
|
||||
) -> Result<(), SystemError>;
|
||||
|
||||
/// ## 显示字符串
|
||||
///
|
||||
/// ### 参数
|
||||
/// ### y: 起始位置y坐标
|
||||
/// ### x: 起始位置的x坐标、
|
||||
/// ### fg: 前景色
|
||||
/// ### bg: 背景色
|
||||
fn put_string(
|
||||
&self,
|
||||
vc_data: &VirtualConsoleData,
|
||||
data: &[u16],
|
||||
count: u32,
|
||||
y: u32,
|
||||
x: u32,
|
||||
fg: u32,
|
||||
bg: u32,
|
||||
) -> Result<(), SystemError>;
|
||||
|
||||
fn cursor(&self, vc_data: &VirtualConsoleData, op: CursorOperation, fg: u32, bg: u32);
|
||||
}
|
||||
|
||||
/// 表示 framebuffer 控制台与低级帧缓冲设备之间接口的数据结构
|
||||
#[derive(Debug, Default)]
|
||||
pub struct FbConsoleDisplay {
|
||||
/// 硬件滚动的行数
|
||||
pub yscroll: u32,
|
||||
/// 光标
|
||||
pub cursor_shape: VcCursor,
|
||||
/// 滚动模式
|
||||
pub scroll_mode: ScrollMode,
|
||||
virt_rows: u32,
|
||||
}
|
||||
|
||||
impl FbConsoleDisplay {
|
||||
pub fn real_y(&self, mut ypos: u32) -> u32 {
|
||||
let rows = self.virt_rows;
|
||||
ypos += self.yscroll;
|
||||
if ypos < rows {
|
||||
return ypos;
|
||||
} else {
|
||||
return ypos - rows;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct FbConAttr:u8 {
|
||||
const UNDERLINE = 1;
|
||||
const REVERSE = 2;
|
||||
const BOLD = 4;
|
||||
}
|
||||
}
|
||||
|
||||
impl FbConAttr {
|
||||
pub fn get_attr(c: u16, color_depth: u32) -> Self {
|
||||
let mut attr = Self::empty();
|
||||
if color_depth == 1 {
|
||||
if Self::underline(c) {
|
||||
attr.insert(Self::UNDERLINE);
|
||||
}
|
||||
if Self::reverse(c) {
|
||||
attr.intersects(Self::REVERSE);
|
||||
}
|
||||
if Self::blod(c) {
|
||||
attr.insert(Self::BOLD);
|
||||
}
|
||||
}
|
||||
attr
|
||||
}
|
||||
|
||||
pub fn update_attr(&self, dst: &mut [u8], src: &[u8], vc_data: &VirtualConsoleData) {
|
||||
let mut offset = if vc_data.font.height < 10 { 1 } else { 2 } as usize;
|
||||
|
||||
let width = (vc_data.font.width + 7) / 8;
|
||||
let cellsize = (vc_data.font.height * width) as usize;
|
||||
|
||||
// 大于offset的部分就是下划线
|
||||
offset = cellsize - (offset * width as usize);
|
||||
for i in 0..cellsize {
|
||||
let mut c = src[i];
|
||||
if self.contains(Self::UNDERLINE) && i >= offset {
|
||||
// 下划线
|
||||
c = 0xff;
|
||||
}
|
||||
if self.contains(Self::BOLD) {
|
||||
c |= c >> 1;
|
||||
}
|
||||
if self.contains(Self::REVERSE) {
|
||||
c = !c;
|
||||
}
|
||||
|
||||
dst[i] = c;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn underline(c: u16) -> bool {
|
||||
c & 0x400 != 0
|
||||
}
|
||||
|
||||
pub fn blod(c: u16) -> bool {
|
||||
c & 0x200 != 0
|
||||
}
|
||||
|
||||
pub fn reverse(c: u16) -> bool {
|
||||
c & 0x800 != 0
|
||||
}
|
||||
}
|
@ -1,13 +1,24 @@
|
||||
use alloc::{string::String, sync::Arc};
|
||||
use alloc::{string::String, sync::Arc, vec::Vec};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
driver::base::device::Device,
|
||||
driver::{base::device::Device, tty::virtual_terminal::Color},
|
||||
init::boot_params,
|
||||
libs::rwlock::RwLock,
|
||||
mm::{ucontext::LockedVMA, PhysAddr, VirtAddr},
|
||||
};
|
||||
|
||||
use self::fbmem::{FbDevice, FrameBufferManager};
|
||||
|
||||
const COLOR_TABLE_8: &'static [u32] = &[
|
||||
0x00000000, 0xff000000, 0x00ff0000, 0xffff0000, 0x0000ff00, 0xff00ff00, 0x00ffff00, 0xffffff00,
|
||||
0x000000ff, 0xff0000ff, 0x00ff00ff, 0xffff00ff, 0x0000ffff, 0xff00ffff, 0x00ffffff, 0xffffffff,
|
||||
];
|
||||
|
||||
const COLOR_TABLE_16: &'static [u32] = &[0x00000000, 0xffff0000, 0x0000ffff, 0xffffffff];
|
||||
|
||||
const COLOR_TABLE_32: &'static [u32] = &[0x00000000, 0xffffffff];
|
||||
|
||||
pub mod fbcon;
|
||||
pub mod fbmem;
|
||||
pub mod fbsysfs;
|
||||
@ -16,6 +27,14 @@ pub mod modedb;
|
||||
// 帧缓冲区id
|
||||
int_like!(FbId, u32);
|
||||
|
||||
lazy_static! {
|
||||
pub static ref FRAME_BUFFER_SET: RwLock<Vec<Option<Arc<dyn FrameBuffer>>>> = {
|
||||
let mut ret = Vec::new();
|
||||
ret.resize(FrameBufferManager::FB_MAX, None);
|
||||
RwLock::new(ret)
|
||||
};
|
||||
}
|
||||
|
||||
impl FbId {
|
||||
/// 帧缓冲区id的初始值(无效值)
|
||||
pub const INIT: Self = Self::new(u32::MAX);
|
||||
@ -37,10 +56,240 @@ pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device {
|
||||
|
||||
/// 设置帧缓冲区的id
|
||||
fn set_fb_id(&self, id: FbId);
|
||||
|
||||
/// 通用的软件图像绘画
|
||||
fn generic_imageblit(&self, image: &FbImage) {
|
||||
let boot_param = boot_params().read();
|
||||
let x = image.x;
|
||||
let y = image.y;
|
||||
let byte_per_pixel = core::mem::size_of::<u32>() as u32;
|
||||
let bit_per_pixel = self.current_fb_var().bits_per_pixel;
|
||||
|
||||
// 计算图像在帧缓冲中的起始位
|
||||
let mut bitstart = (y * self.current_fb_fix().line_length * 8) + (x * bit_per_pixel);
|
||||
let start_index = bitstart & (32 - 1);
|
||||
let pitch_index = (self.current_fb_fix().line_length & (byte_per_pixel - 1)) * 8;
|
||||
// 位转字节
|
||||
bitstart /= 8;
|
||||
|
||||
// 对齐到像素字节大小
|
||||
bitstart &= !(byte_per_pixel - 1);
|
||||
|
||||
let dst1 = boot_param.screen_info.lfb_virt_base;
|
||||
if dst1.is_none() {
|
||||
return;
|
||||
}
|
||||
let mut dst1 = dst1.unwrap();
|
||||
dst1 = dst1 + VirtAddr::new(bitstart as usize);
|
||||
|
||||
let _ = self.fb_sync();
|
||||
|
||||
if image.depth == 1 {
|
||||
let fg;
|
||||
let bg;
|
||||
if self.current_fb_fix().visual == FbVisual::TrueColor
|
||||
|| self.current_fb_fix().visual == FbVisual::DirectColor
|
||||
{
|
||||
let fb_info_data = self.framebuffer_info_data().read();
|
||||
fg = fb_info_data.pesudo_palette[image.fg as usize];
|
||||
bg = fb_info_data.pesudo_palette[image.bg as usize];
|
||||
} else {
|
||||
fg = image.fg;
|
||||
bg = image.bg;
|
||||
}
|
||||
|
||||
if 32 % bit_per_pixel == 0
|
||||
&& start_index == 0
|
||||
&& pitch_index == 0
|
||||
&& image.width & (32 / bit_per_pixel - 1) == 0
|
||||
&& bit_per_pixel >= 8
|
||||
&& bit_per_pixel <= 32
|
||||
{
|
||||
unsafe { self.fast_imageblit(image, dst1, fg, bg) }
|
||||
} else {
|
||||
self.slow_imageblit(image, dst1, fg, bg, start_index, pitch_index)
|
||||
}
|
||||
} else {
|
||||
todo!("color image blit todo");
|
||||
}
|
||||
}
|
||||
|
||||
/// 优化的单色图像绘制函数
|
||||
///
|
||||
/// 仅当 bits_per_pixel 为 8、16 或 32 时才能使用。
|
||||
/// 要求 image->width 可以被像素或 dword (ppw) 整除。
|
||||
/// 要求 fix->line_length 可以被 4 整除。
|
||||
/// 扫描线的开始和结束都是 dword 对齐的。
|
||||
unsafe fn fast_imageblit(&self, image: &FbImage, mut dst1: VirtAddr, fg: u32, bg: u32) {
|
||||
let bpp = self.current_fb_var().bits_per_pixel;
|
||||
let mut fgx = fg;
|
||||
let mut bgx = bg;
|
||||
let ppw = 32 / bpp;
|
||||
let spitch = (image.width + 7) / 8;
|
||||
let tab: &[u32];
|
||||
let mut color_tab: [u32; 16] = [0; 16];
|
||||
|
||||
match bpp {
|
||||
8 => {
|
||||
tab = COLOR_TABLE_8;
|
||||
}
|
||||
16 => {
|
||||
tab = COLOR_TABLE_16;
|
||||
}
|
||||
32 => {
|
||||
tab = COLOR_TABLE_32;
|
||||
}
|
||||
_ => {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for _ in (0..(ppw - 1)).rev() {
|
||||
fgx <<= bpp;
|
||||
bgx <<= bpp;
|
||||
fgx |= fg;
|
||||
bgx |= bg;
|
||||
}
|
||||
|
||||
let bitmask = (1 << ppw) - 1;
|
||||
let eorx = fgx ^ bgx;
|
||||
let k = image.width / ppw;
|
||||
|
||||
for (idx, val) in tab.iter().enumerate() {
|
||||
color_tab[idx] = (*val & eorx) ^ bgx;
|
||||
}
|
||||
|
||||
let mut dst;
|
||||
let mut shift;
|
||||
let mut src;
|
||||
let mut offset = 0;
|
||||
let mut j = 0;
|
||||
for _ in (0..image.height).rev() {
|
||||
dst = dst1.as_ptr::<u32>();
|
||||
shift = 8;
|
||||
src = offset;
|
||||
match ppw {
|
||||
4 => {
|
||||
// 8bpp
|
||||
j = k;
|
||||
while j >= 2 {
|
||||
*dst = color_tab[(image.data[src] as usize >> 4) & bitmask];
|
||||
dst = dst.add(1);
|
||||
*dst = color_tab[(image.data[src] as usize >> 0) & bitmask];
|
||||
dst = dst.add(1);
|
||||
j -= 2;
|
||||
src += 1;
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
// 16bpp
|
||||
j = k;
|
||||
while j >= 4 {
|
||||
*dst = color_tab[(image.data[src] as usize >> 6) & bitmask];
|
||||
dst = dst.add(1);
|
||||
*dst = color_tab[(image.data[src] as usize >> 4) & bitmask];
|
||||
dst = dst.add(1);
|
||||
*dst = color_tab[(image.data[src] as usize >> 2) & bitmask];
|
||||
dst = dst.add(1);
|
||||
*dst = color_tab[(image.data[src] as usize >> 0) & bitmask];
|
||||
dst = dst.add(1);
|
||||
src += 1;
|
||||
j -= 4;
|
||||
}
|
||||
}
|
||||
1 => {
|
||||
// 32 bpp
|
||||
j = k;
|
||||
while j >= 8 {
|
||||
*dst = color_tab[(image.data[src] as usize >> 7) & bitmask];
|
||||
dst = dst.add(1);
|
||||
*dst = color_tab[(image.data[src] as usize >> 6) & bitmask];
|
||||
dst = dst.add(1);
|
||||
*dst = color_tab[(image.data[src] as usize >> 5) & bitmask];
|
||||
dst = dst.add(1);
|
||||
*dst = color_tab[(image.data[src] as usize >> 4) & bitmask];
|
||||
dst = dst.add(1);
|
||||
*dst = color_tab[(image.data[src] as usize >> 3) & bitmask];
|
||||
dst = dst.add(1);
|
||||
*dst = color_tab[(image.data[src] as usize >> 2) & bitmask];
|
||||
dst = dst.add(1);
|
||||
*dst = color_tab[(image.data[src] as usize >> 1) & bitmask];
|
||||
dst = dst.add(1);
|
||||
*dst = color_tab[(image.data[src] as usize >> 0) & bitmask];
|
||||
dst = dst.add(1);
|
||||
src += 1;
|
||||
j -= 8;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
while j != 0 {
|
||||
shift -= ppw;
|
||||
*dst = color_tab[(image.data[src] as usize >> shift) & bitmask];
|
||||
dst = dst.add(1);
|
||||
if shift == 0 {
|
||||
shift = 8;
|
||||
src += 1;
|
||||
}
|
||||
}
|
||||
|
||||
dst1 += VirtAddr::new(self.current_fb_fix().line_length as usize);
|
||||
offset += spitch as usize;
|
||||
}
|
||||
}
|
||||
|
||||
fn slow_imageblit(
|
||||
&self,
|
||||
_image: &FbImage,
|
||||
_dst1: VirtAddr,
|
||||
_fg: u32,
|
||||
_bg: u32,
|
||||
_start_index: u32,
|
||||
_pitch_index: u32,
|
||||
) {
|
||||
todo!();
|
||||
// let bpp = self.current_fb_var().bits_per_pixel;
|
||||
// let pitch = self.current_fb_fix().line_length;
|
||||
// let null_bits = 32 - bpp;
|
||||
// let spitch = (image.width + 7) / 8;
|
||||
|
||||
// // TODO:这里是需要计算的,但是目前用不到,先直接写
|
||||
// let bswapmask = 0;
|
||||
|
||||
// let dst2 = dst1;
|
||||
|
||||
// // 一行一行画
|
||||
// for i in image.height..0 {
|
||||
// let dst = dst1;
|
||||
|
||||
// if start_index > 0 {
|
||||
// let start_mask = !(!(0 as u32) << start_index);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct FrameBufferInfoData {
|
||||
/// 颜色映射
|
||||
pub color_map: Vec<Color>,
|
||||
/// 颜色映射表
|
||||
pub pesudo_palette: Vec<u32>,
|
||||
}
|
||||
|
||||
impl FrameBufferInfoData {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 帧缓冲区信息
|
||||
pub trait FrameBufferInfo {
|
||||
pub trait FrameBufferInfo: FrameBufferOps {
|
||||
fn framebuffer_info_data(&self) -> &RwLock<FrameBufferInfoData>;
|
||||
|
||||
/// Amount of ioremapped VRAM or 0
|
||||
fn screen_size(&self) -> usize;
|
||||
|
||||
@ -61,6 +310,54 @@ pub trait FrameBufferInfo {
|
||||
|
||||
/// 获取帧缓冲区的状态
|
||||
fn state(&self) -> FbState;
|
||||
|
||||
/// 颜色位深
|
||||
fn color_depth(&self) -> u32 {
|
||||
return 8;
|
||||
|
||||
// 以下逻辑没问题,但是当前没有初始化好var,所以先直接返回当前vasafb的8
|
||||
|
||||
// let var = self.current_fb_var();
|
||||
// let fix = self.current_fb_fix();
|
||||
// if fix.visual == FbVisual::Mono01 || fix.visual == FbVisual::Mono10 {
|
||||
// return 1;
|
||||
// } else {
|
||||
// if var.green.length == var.blue.length
|
||||
// && var.green.length == var.red.length
|
||||
// && var.green.offset == var.blue.offset
|
||||
// && var.green.offset == var.red.offset
|
||||
// {
|
||||
// kerror!("return {}", var.green.length);
|
||||
// return var.green.length;
|
||||
// } else {
|
||||
// return var.green.length + var.blue.length + var.red.length;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
/// ## 设置调色板
|
||||
fn set_color_map(&self, cmap: Vec<Color>) -> Result<(), SystemError> {
|
||||
let ret = self.fb_set_color_map(cmap.clone());
|
||||
if ret.is_err() && ret.clone().unwrap_err() == SystemError::ENOSYS {
|
||||
for (idx, color) in cmap.iter().enumerate() {
|
||||
if self
|
||||
.fb_set_color_register(idx as u16, color.red, color.green, color.blue)
|
||||
.is_err()
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self.framebuffer_info_data().write().color_map = cmap;
|
||||
} else {
|
||||
if ret.is_ok() {
|
||||
self.framebuffer_info_data().write().color_map = cmap;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// 帧缓冲区操作
|
||||
@ -122,6 +419,45 @@ pub trait FrameBufferOps {
|
||||
|
||||
/// 卸载与该帧缓冲区相关的所有资源
|
||||
fn fb_destroy(&self);
|
||||
|
||||
/// 画光标
|
||||
fn fb_cursor(&self, _cursor: &FbCursor) -> Result<(), SystemError> {
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
|
||||
/// 画软光标(暂时简要实现)
|
||||
fn soft_cursor(&self, cursor: FbCursor) -> Result<(), SystemError> {
|
||||
let mut image = cursor.image.clone();
|
||||
if cursor.enable {
|
||||
match cursor.rop {
|
||||
true => {
|
||||
for i in 0..image.data.len() {
|
||||
image.data[i] ^= cursor.mask[i];
|
||||
}
|
||||
}
|
||||
false => {
|
||||
for i in 0..image.data.len() {
|
||||
image.data[i] &= cursor.mask[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = self.fb_image_blit(&image);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fb_sync(&self) -> Result<(), SystemError> {
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
|
||||
/// 绘画位图
|
||||
fn fb_image_blit(&self, image: &FbImage);
|
||||
|
||||
fn fb_set_color_map(&self, _cmap: Vec<Color>) -> Result<(), SystemError> {
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
}
|
||||
|
||||
/// 帧缓冲区的状态
|
||||
@ -197,25 +533,27 @@ pub enum FillRectROP {
|
||||
}
|
||||
|
||||
/// `CopyAreaData` 结构体用于表示一个矩形区域,并指定从哪个源位置复制数据。
|
||||
///
|
||||
/// 注意,源位置必须是有意义的(即包围的矩形都必须得在屏幕内)
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct CopyAreaData {
|
||||
/// 目标矩形左上角的x坐标
|
||||
pub dx: u32,
|
||||
pub dx: i32,
|
||||
/// 目标矩形左上角的y坐标
|
||||
pub dy: u32,
|
||||
pub dy: i32,
|
||||
/// 矩形的宽度
|
||||
pub width: u32,
|
||||
/// 矩形的高度
|
||||
pub height: u32,
|
||||
/// 源矩形左上角的x坐标
|
||||
pub sx: u32,
|
||||
pub sx: i32,
|
||||
/// 源矩形左上角的y坐标
|
||||
pub sy: u32,
|
||||
pub sy: i32,
|
||||
}
|
||||
|
||||
impl CopyAreaData {
|
||||
#[allow(dead_code)]
|
||||
pub fn new(dx: u32, dy: u32, width: u32, height: u32, sx: u32, sy: u32) -> Self {
|
||||
pub fn new(dx: i32, dy: i32, width: u32, height: u32, sx: i32, sy: i32) -> Self {
|
||||
Self {
|
||||
dx,
|
||||
dy,
|
||||
@ -850,3 +1188,72 @@ pub enum BootTimeVideoType {
|
||||
/// EFI graphic mode
|
||||
Efi,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct FbCursor {
|
||||
/// 设置选项
|
||||
pub set_mode: FbCursorSetMode,
|
||||
/// 开关选项
|
||||
pub enable: bool,
|
||||
/// 表示光标图像的位操作,true表示XOR,false表示COPY
|
||||
pub rop: bool,
|
||||
/// 表示光标掩码(mask)的数据。掩码用于定义光标的形状,指定了哪些像素是光标的一部分。
|
||||
pub mask: Vec<u8>,
|
||||
|
||||
/// 表示光标的热点位置,即在光标图像中被认为是"焦点"的位置
|
||||
pub hot_x: u32,
|
||||
pub hot_y: u32,
|
||||
|
||||
/// 光标图像
|
||||
pub image: FbImage,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// 硬件光标控制
|
||||
#[derive(Default)]
|
||||
pub struct FbCursorSetMode:u8 {
|
||||
/// 设置位图
|
||||
const FB_CUR_SETIMAGE = 0x01;
|
||||
/// 设置位置
|
||||
const FB_CUR_SETPOS = 0x02;
|
||||
/// 设置热点
|
||||
const FB_CUR_SETHOT = 0x04;
|
||||
/// ColorMap
|
||||
const FB_CUR_SETCMAP = 0x08;
|
||||
/// 形状
|
||||
const FB_CUR_SETSHAPE = 0x10;
|
||||
/// Size
|
||||
const FB_CUR_SETSIZE = 0x20;
|
||||
/// 全设置
|
||||
const FB_CUR_SETALL = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ScrollMode {
|
||||
Move,
|
||||
PanMove,
|
||||
WrapMove,
|
||||
Redraw,
|
||||
PanRedraw,
|
||||
}
|
||||
|
||||
impl Default for ScrollMode {
|
||||
/// ## 默认Move
|
||||
fn default() -> Self {
|
||||
Self::Move
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct FbImage {
|
||||
pub x: u32,
|
||||
pub y: u32,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub fg: u32,
|
||||
pub bg: u32,
|
||||
pub depth: u8,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
@ -28,8 +28,8 @@ use crate::{
|
||||
CompatibleTable,
|
||||
},
|
||||
},
|
||||
tty::serial::serial8250::send_to_default_serial8250_port,
|
||||
video::fbdev::base::{fbmem::frame_buffer_manager, FbVisual},
|
||||
serial::serial8250::send_to_default_serial8250_port,
|
||||
video::fbdev::base::{fbmem::frame_buffer_manager, FbVisual, FRAME_BUFFER_SET},
|
||||
},
|
||||
filesystem::{
|
||||
kernfs::KernFSInode,
|
||||
@ -56,7 +56,7 @@ use crate::{
|
||||
use super::base::{
|
||||
fbmem::FbDevice, BlankMode, BootTimeVideoType, FbAccel, FbActivateFlags, FbId, FbState, FbType,
|
||||
FbVModeFlags, FbVarScreenInfo, FbVideoMode, FixedScreenInfo, FrameBuffer, FrameBufferInfo,
|
||||
FrameBufferOps,
|
||||
FrameBufferInfoData, FrameBufferOps,
|
||||
};
|
||||
|
||||
/// 当前机器上面是否有vesa帧缓冲区
|
||||
@ -89,11 +89,14 @@ lazy_static! {
|
||||
pub struct VesaFb {
|
||||
inner: SpinLock<InnerVesaFb>,
|
||||
kobj_state: LockedKObjectState,
|
||||
fb_data: RwLock<FrameBufferInfoData>,
|
||||
}
|
||||
|
||||
impl VesaFb {
|
||||
pub const NAME: &'static str = "vesa_vga";
|
||||
pub fn new() -> Self {
|
||||
let mut fb_info_data = FrameBufferInfoData::new();
|
||||
fb_info_data.pesudo_palette.resize(256, 0);
|
||||
return Self {
|
||||
inner: SpinLock::new(InnerVesaFb {
|
||||
bus: None,
|
||||
@ -111,6 +114,7 @@ impl VesaFb {
|
||||
fb_state: FbState::Suspended,
|
||||
}),
|
||||
kobj_state: LockedKObjectState::new(None),
|
||||
fb_data: RwLock::new(fb_info_data),
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -281,12 +285,46 @@ impl FrameBufferOps for VesaFb {
|
||||
|
||||
fn fb_set_color_register(
|
||||
&self,
|
||||
_regno: u16,
|
||||
_red: u16,
|
||||
_green: u16,
|
||||
_blue: u16,
|
||||
regno: u16,
|
||||
mut red: u16,
|
||||
mut green: u16,
|
||||
mut blue: u16,
|
||||
) -> Result<(), SystemError> {
|
||||
todo!()
|
||||
let mut fb_data = self.framebuffer_info_data().write();
|
||||
let var = self.current_fb_var();
|
||||
if regno as usize >= fb_data.pesudo_palette.len() {
|
||||
return Err(SystemError::E2BIG);
|
||||
}
|
||||
|
||||
if var.bits_per_pixel == 8 {
|
||||
todo!("vesa_setpalette todo");
|
||||
} else if regno < 16 {
|
||||
match var.bits_per_pixel {
|
||||
16 => {
|
||||
if var.red.offset == 10 {
|
||||
// RGB 1:5:5:5
|
||||
fb_data.pesudo_palette[regno as usize] = ((red as u32 & 0xf800) >> 1)
|
||||
| ((green as u32 & 0xf800) >> 6)
|
||||
| ((blue as u32 & 0xf800) >> 11);
|
||||
} else {
|
||||
fb_data.pesudo_palette[regno as usize] = (red as u32 & 0xf800)
|
||||
| ((green as u32 & 0xfc00) >> 5)
|
||||
| ((blue as u32 & 0xf800) >> 11);
|
||||
}
|
||||
}
|
||||
24 | 32 => {
|
||||
red >>= 8;
|
||||
green >>= 8;
|
||||
blue >>= 8;
|
||||
fb_data.pesudo_palette[regno as usize] = ((red as u32) << var.red.offset)
|
||||
| ((green as u32) << var.green.offset)
|
||||
| ((blue as u32) << var.blue.offset);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fb_blank(&self, _blank_mode: BlankMode) -> Result<(), SystemError> {
|
||||
@ -338,6 +376,138 @@ impl FrameBufferOps for VesaFb {
|
||||
|
||||
return Ok(len);
|
||||
}
|
||||
|
||||
fn fb_image_blit(&self, image: &super::base::FbImage) {
|
||||
self.generic_imageblit(image);
|
||||
}
|
||||
|
||||
/// ## 填充矩形
|
||||
fn fb_fillrect(&self, rect: super::base::FillRectData) -> Result<(), SystemError> {
|
||||
// kwarn!("rect {rect:?}");
|
||||
|
||||
let boot_param = boot_params().read();
|
||||
let screen_base = boot_param
|
||||
.screen_info
|
||||
.lfb_virt_base
|
||||
.ok_or(SystemError::ENODEV)?;
|
||||
let fg;
|
||||
if self.current_fb_fix().visual == FbVisual::TrueColor
|
||||
|| self.current_fb_fix().visual == FbVisual::DirectColor
|
||||
{
|
||||
fg = self.fb_data.read().pesudo_palette[rect.color as usize];
|
||||
} else {
|
||||
fg = rect.color;
|
||||
}
|
||||
|
||||
let bpp = self.current_fb_var().bits_per_pixel;
|
||||
// 每行像素数
|
||||
let line_offset = self.current_fb_var().xres;
|
||||
match bpp {
|
||||
32 => {
|
||||
let base = screen_base.as_ptr::<u32>();
|
||||
|
||||
for y in rect.dy..(rect.dy + rect.height) {
|
||||
for x in rect.dx..(rect.dx + rect.width) {
|
||||
unsafe { *base.add((y * line_offset + x) as usize) = fg };
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fb_copyarea(&self, data: super::base::CopyAreaData) -> Result<(), SystemError> {
|
||||
let bp = boot_params().read();
|
||||
let base = bp.screen_info.lfb_virt_base.ok_or(SystemError::ENODEV)?;
|
||||
let var = self.current_fb_var();
|
||||
|
||||
if data.sx < 0
|
||||
|| data.sy < 0
|
||||
|| data.sx as u32 > var.xres
|
||||
|| data.sx as u32 + data.width > var.xres
|
||||
|| data.sy as u32 > var.yres
|
||||
|| data.sy as u32 + data.height > var.yres
|
||||
{
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let bytes_per_pixel = var.bits_per_pixel >> 3;
|
||||
let bytes_per_line = var.xres * bytes_per_pixel;
|
||||
|
||||
let sy = data.sy as u32;
|
||||
let sx = data.sx as u32;
|
||||
|
||||
let dst = {
|
||||
let mut dst = base;
|
||||
if data.dy < 0 {
|
||||
dst -= VirtAddr::new((((-data.dy) as u32) * bytes_per_line) as usize);
|
||||
} else {
|
||||
dst += VirtAddr::new(((data.dy as u32) * bytes_per_line) as usize);
|
||||
}
|
||||
|
||||
if data.dx > 0 && (data.dx as u32) < var.xres {
|
||||
dst += VirtAddr::new(((data.dx as u32) * bytes_per_pixel) as usize);
|
||||
}
|
||||
|
||||
dst
|
||||
};
|
||||
let src = base + VirtAddr::new((sy * bytes_per_line + sx * bytes_per_pixel) as usize);
|
||||
|
||||
match bytes_per_pixel {
|
||||
4 => {
|
||||
// 32bpp
|
||||
let mut dst = dst.as_ptr::<u32>();
|
||||
let mut src = src.as_ptr::<u32>();
|
||||
|
||||
for y in 0..data.height as usize {
|
||||
if (data.dy + y as i32) < 0 || (data.dy + y as i32) > var.yres as i32 {
|
||||
unsafe {
|
||||
// core::ptr::copy(src, dst, data.width as usize);
|
||||
src = src.add(var.xres as usize);
|
||||
dst = dst.add(var.xres as usize);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if data.dx < 0 {
|
||||
if ((-data.dx) as u32) < data.width {
|
||||
unsafe {
|
||||
core::ptr::copy(
|
||||
src.add((-data.dx) as usize),
|
||||
dst,
|
||||
(data.width as usize) - (-data.dx) as usize,
|
||||
);
|
||||
src = src.add(var.xres as usize);
|
||||
dst = dst.add(var.xres as usize);
|
||||
}
|
||||
}
|
||||
} else if data.dx as u32 + data.width > var.xres {
|
||||
if (data.dx as u32) < var.xres {
|
||||
unsafe {
|
||||
core::ptr::copy(src, dst, (var.xres - data.dx as u32) as usize);
|
||||
src = src.add(var.xres as usize);
|
||||
dst = dst.add(var.xres as usize);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i in 0..data.width as usize {
|
||||
unsafe { *(dst.add(i)) = *(src.add(i)) }
|
||||
}
|
||||
unsafe {
|
||||
// core::ptr::copy(src, dst, data.width as usize);
|
||||
src = src.add(var.xres as usize);
|
||||
dst = dst.add(var.xres as usize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl FrameBufferInfo for VesaFb {
|
||||
@ -368,6 +538,10 @@ impl FrameBufferInfo for VesaFb {
|
||||
fn state(&self) -> FbState {
|
||||
self.inner.lock().fb_state
|
||||
}
|
||||
|
||||
fn framebuffer_info_data(&self) -> &RwLock<FrameBufferInfoData> {
|
||||
&self.fb_data
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -679,36 +853,54 @@ fn vesa_fb_device_init() -> Result<(), SystemError> {
|
||||
static INIT: Once = Once::new();
|
||||
INIT.call_once(|| {
|
||||
kinfo!("vesa fb device init");
|
||||
let device = Arc::new(VesaFb::new());
|
||||
|
||||
let mut fix_info_guard = VESAFB_FIX_INFO.write_irqsave();
|
||||
let mut var_info_guard = VESAFB_DEFINED.write_irqsave();
|
||||
let mut fb_fix = VESAFB_FIX_INFO.write_irqsave();
|
||||
let mut fb_var = VESAFB_DEFINED.write_irqsave();
|
||||
|
||||
let boot_params_guard = boot_params().read();
|
||||
let boottime_screen_info = &boot_params_guard.screen_info;
|
||||
|
||||
fix_info_guard.smem_start = Some(boottime_screen_info.lfb_base);
|
||||
fix_info_guard.smem_len = boottime_screen_info.lfb_size;
|
||||
fb_fix.smem_start = Some(boottime_screen_info.lfb_base);
|
||||
fb_fix.smem_len = boottime_screen_info.lfb_size;
|
||||
|
||||
if boottime_screen_info.video_type == BootTimeVideoType::Mda {
|
||||
fix_info_guard.visual = FbVisual::Mono10;
|
||||
var_info_guard.bits_per_pixel = 8;
|
||||
fix_info_guard.line_length = (boottime_screen_info.origin_video_cols as u32)
|
||||
* (var_info_guard.bits_per_pixel / 8);
|
||||
var_info_guard.xres_virtual = boottime_screen_info.origin_video_cols as u32;
|
||||
var_info_guard.yres_virtual = boottime_screen_info.origin_video_lines as u32;
|
||||
fb_fix.visual = FbVisual::Mono10;
|
||||
fb_var.bits_per_pixel = 8;
|
||||
fb_fix.line_length =
|
||||
(boottime_screen_info.origin_video_cols as u32) * (fb_var.bits_per_pixel / 8);
|
||||
fb_var.xres_virtual = boottime_screen_info.origin_video_cols as u32;
|
||||
fb_var.yres_virtual = boottime_screen_info.origin_video_lines as u32;
|
||||
} else {
|
||||
fix_info_guard.visual = FbVisual::TrueColor;
|
||||
var_info_guard.bits_per_pixel = boottime_screen_info.lfb_depth as u32;
|
||||
fix_info_guard.line_length =
|
||||
(boottime_screen_info.lfb_width as u32) * (var_info_guard.bits_per_pixel / 8);
|
||||
var_info_guard.xres_virtual = boottime_screen_info.lfb_width as u32;
|
||||
var_info_guard.yres_virtual = boottime_screen_info.lfb_height as u32;
|
||||
fb_fix.visual = FbVisual::TrueColor;
|
||||
fb_var.bits_per_pixel = boottime_screen_info.lfb_depth as u32;
|
||||
fb_fix.line_length =
|
||||
(boottime_screen_info.lfb_width as u32) * (fb_var.bits_per_pixel / 8);
|
||||
fb_var.xres_virtual = boottime_screen_info.lfb_width as u32;
|
||||
fb_var.yres_virtual = boottime_screen_info.lfb_height as u32;
|
||||
fb_var.xres = boottime_screen_info.lfb_width as u32;
|
||||
fb_var.yres = boottime_screen_info.lfb_height as u32;
|
||||
}
|
||||
|
||||
drop(var_info_guard);
|
||||
drop(fix_info_guard);
|
||||
fb_var.red.length = boottime_screen_info.red_size as u32;
|
||||
fb_var.green.length = boottime_screen_info.green_size as u32;
|
||||
fb_var.blue.length = boottime_screen_info.blue_size as u32;
|
||||
|
||||
fb_var.red.offset = boottime_screen_info.red_pos as u32;
|
||||
fb_var.green.offset = boottime_screen_info.green_pos as u32;
|
||||
fb_var.blue.offset = boottime_screen_info.blue_pos as u32;
|
||||
|
||||
// TODO: 这里是暂时这样写的,初始化为RGB888格式,后续vesa初始化完善后删掉下面
|
||||
fb_var.red.offset = 16;
|
||||
fb_var.green.offset = 8;
|
||||
fb_var.blue.offset = 0;
|
||||
|
||||
if fb_var.bits_per_pixel >= 1 && fb_var.bits_per_pixel <= 8 {
|
||||
fb_var.red.length = fb_var.bits_per_pixel;
|
||||
fb_var.green.length = fb_var.bits_per_pixel;
|
||||
fb_var.blue.length = fb_var.bits_per_pixel;
|
||||
}
|
||||
|
||||
let device = Arc::new(VesaFb::new());
|
||||
device_manager().device_default_initialize(&(device.clone() as Arc<dyn Device>));
|
||||
|
||||
platform_device_manager()
|
||||
@ -719,6 +911,16 @@ fn vesa_fb_device_init() -> Result<(), SystemError> {
|
||||
.register_fb(device.clone() as Arc<dyn FrameBuffer>)
|
||||
.expect("vesa_fb_device_init: frame_buffer_manager().register_fb failed");
|
||||
|
||||
// 加入全局fb表
|
||||
let mut guard = FRAME_BUFFER_SET.write();
|
||||
if guard.get(device.fb_id().data() as usize).unwrap().is_some() {
|
||||
kwarn!(
|
||||
"vesa_fb_device_init: There is already an element {:?} in the FRAME_BUFFER_SET",
|
||||
device.fb_id()
|
||||
);
|
||||
}
|
||||
guard[device.fb_id().data() as usize] = Some(device.clone());
|
||||
|
||||
// 设置vesa fb的状态为运行中
|
||||
device.inner.lock().fb_state = FbState::Running;
|
||||
});
|
||||
|
@ -2,7 +2,6 @@ use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use crate::{
|
||||
arch::MMArch,
|
||||
driver::tty::serial::serial8250::send_to_default_serial8250_port,
|
||||
init::boot_params,
|
||||
kinfo,
|
||||
libs::{
|
||||
@ -176,7 +175,10 @@ impl VideoRefreshManager {
|
||||
pub unsafe fn video_init() -> Result<(), SystemError> {
|
||||
use crate::{
|
||||
arch::driver::video::arch_video_early_init,
|
||||
driver::video::fbdev::base::BootTimeVideoType,
|
||||
driver::{
|
||||
serial::serial8250::send_to_default_serial8250_port,
|
||||
video::fbdev::base::BootTimeVideoType,
|
||||
},
|
||||
};
|
||||
|
||||
arch_video_early_init()?;
|
||||
|
Reference in New Issue
Block a user