mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-25 18:23:22 +00:00
添加帧缓冲区抽象并实现vesafb的驱动 (#483)
- 添加bootparams对象 - 修正由于bus的driver、device强弱引用关系 不正确从而导致对象被释放的bug - 添加vesafb的驱动 - 实现framebuffer抽象层 - 为通用帧缓冲区抽象实现sysfs的属性 - 修改设备号DeviceNumber的定义 - 仿照linux,添加initcall,并在第一个内核线程中,调用他们。
This commit is contained in:
@ -85,7 +85,7 @@ struct InnerFbConsoleDevice {
|
||||
kernfs_inode: Option<Arc<KernFSInode>>,
|
||||
parent: Option<Weak<dyn KObject>>,
|
||||
kset: Option<Arc<KSet>>,
|
||||
bus: Option<Arc<dyn Bus>>,
|
||||
bus: Option<Weak<dyn Bus>>,
|
||||
driver: Option<Weak<dyn Driver>>,
|
||||
ktype: Option<&'static dyn KObjType>,
|
||||
}
|
||||
@ -183,10 +183,14 @@ impl Device for FbConsoleDevice {
|
||||
IdTable::new(Self::NAME.to_string(), None)
|
||||
}
|
||||
|
||||
fn set_bus(&self, bus: Option<Arc<dyn Bus>>) {
|
||||
fn set_bus(&self, bus: Option<Weak<dyn Bus>>) {
|
||||
self.inner.lock().bus = bus;
|
||||
}
|
||||
|
||||
fn bus(&self) -> Option<Weak<dyn Bus>> {
|
||||
self.inner.lock().bus.clone()
|
||||
}
|
||||
|
||||
fn set_class(&self, _class: Option<Arc<dyn Class>>) {
|
||||
// 不允许修改
|
||||
kwarn!("fbcon's class can not be changed");
|
||||
|
@ -1,23 +1,45 @@
|
||||
use core::intrinsics::unlikely;
|
||||
|
||||
use alloc::{
|
||||
string::ToString,
|
||||
string::{String, ToString},
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
|
||||
use system_error::SystemError;
|
||||
use unified_init::macros::unified_init;
|
||||
|
||||
use crate::driver::base::{
|
||||
class::{class_manager, Class},
|
||||
device::sys_dev_char_kset,
|
||||
init::SUBSYSTEM_INITIALIZER_SLICE,
|
||||
kobject::KObject,
|
||||
subsys::SubSysPrivate,
|
||||
use crate::{
|
||||
driver::base::{
|
||||
class::{class_manager, Class},
|
||||
device::{
|
||||
bus::Bus,
|
||||
device_manager,
|
||||
device_number::{DeviceNumber, Major},
|
||||
driver::Driver,
|
||||
sys_dev_char_kset, Device, DeviceType, IdTable,
|
||||
},
|
||||
kobject::{KObjType, KObject, KObjectState, LockedKObjectState},
|
||||
kset::KSet,
|
||||
subsys::SubSysPrivate,
|
||||
},
|
||||
filesystem::{kernfs::KernFSInode, sysfs::AttributeGroup},
|
||||
init::initcall::INITCALL_SUBSYS,
|
||||
libs::{
|
||||
rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
spinlock::SpinLock,
|
||||
},
|
||||
};
|
||||
|
||||
use super::fbcon::fb_console_init;
|
||||
use super::{fbcon::fb_console_init, fbsysfs::FbDeviceAttrGroup, FbId, FrameBuffer};
|
||||
|
||||
/// `/sys/class/graphics` 的 class 实例
|
||||
static mut CLASS_GRAPHICS_INSTANCE: Option<Arc<GraphicsClass>> = None;
|
||||
|
||||
lazy_static! {
|
||||
/// 帧缓冲区管理器
|
||||
static ref FRAME_BUFFER_MANAGER: FrameBufferManager = FrameBufferManager::new();
|
||||
}
|
||||
|
||||
/// 获取 `/sys/class/graphics` 的 class 实例
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
@ -25,8 +47,13 @@ pub fn sys_class_graphics_instance() -> Option<&'static Arc<GraphicsClass>> {
|
||||
unsafe { CLASS_GRAPHICS_INSTANCE.as_ref() }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn frame_buffer_manager() -> &'static FrameBufferManager {
|
||||
&FRAME_BUFFER_MANAGER
|
||||
}
|
||||
|
||||
/// 初始化帧缓冲区子系统
|
||||
#[unified_init(SUBSYSTEM_INITIALIZER_SLICE)]
|
||||
#[unified_init(INITCALL_SUBSYS)]
|
||||
pub fn fbmem_init() -> Result<(), SystemError> {
|
||||
let graphics_class = GraphicsClass::new();
|
||||
class_manager().class_register(&(graphics_class.clone() as Arc<dyn Class>))?;
|
||||
@ -76,3 +103,236 @@ impl Class for GraphicsClass {
|
||||
return &self.subsystem;
|
||||
}
|
||||
}
|
||||
|
||||
/// 帧缓冲区管理器
|
||||
#[derive(Debug)]
|
||||
pub struct FrameBufferManager {
|
||||
inner: RwLock<InnerFrameBufferManager>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InnerFrameBufferManager {
|
||||
/// 已经注册的帧缓冲区
|
||||
registered_fbs: [Option<Arc<dyn FrameBuffer>>; FrameBufferManager::FB_MAX],
|
||||
}
|
||||
|
||||
impl FrameBufferManager {
|
||||
pub const FB_MAX: usize = 32;
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
inner: RwLock::new(InnerFrameBufferManager {
|
||||
registered_fbs: Default::default(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// 注册一个帧缓冲区
|
||||
///
|
||||
/// # 参数
|
||||
///
|
||||
/// - fb: 帧缓冲区
|
||||
pub fn register_fb(&self, fb: Arc<dyn FrameBuffer>) -> Result<FbId, SystemError> {
|
||||
let id = self.generate_fb_id().expect("no more fb id");
|
||||
fb.set_fb_id(id);
|
||||
let fb_device = FbDevice::new(Arc::downgrade(&fb) as Weak<dyn FrameBuffer>, id);
|
||||
device_manager().device_default_initialize(&(fb_device.clone() as Arc<dyn Device>));
|
||||
fb_device.set_parent(Some(Arc::downgrade(&(fb.clone() as Arc<dyn KObject>))));
|
||||
|
||||
fb.set_fb_device(Some(fb_device.clone()));
|
||||
|
||||
device_manager().add_device(fb_device.clone() as Arc<dyn Device>)?;
|
||||
|
||||
// todo: 从Modedb中获取信息
|
||||
// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/video/fbdev/core/fbmem.c#1584
|
||||
|
||||
let mut inner = self.inner.write();
|
||||
inner.registered_fbs[id.data() as usize] = Some(fb.clone() as Arc<dyn FrameBuffer>);
|
||||
|
||||
// todo: 把fb跟fbcon关联起来
|
||||
return Ok(id);
|
||||
}
|
||||
|
||||
/// 注销一个帧缓冲区
|
||||
///
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/video/fbdev/core/fbmem.c#1726
|
||||
#[allow(dead_code)]
|
||||
pub fn unregister_fb(&self, _fb: Arc<dyn FrameBuffer>) -> Result<(), SystemError> {
|
||||
todo!("unregister_fb")
|
||||
}
|
||||
|
||||
/// 根据id查找帧缓冲区
|
||||
pub fn find_fb_by_id(&self, id: FbId) -> Result<Option<Arc<dyn FrameBuffer>>, SystemError> {
|
||||
if unlikely(!id.is_valid()) {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
let inner = self.inner.read();
|
||||
return Ok(inner.registered_fbs[id.data() as usize].clone());
|
||||
}
|
||||
|
||||
fn generate_fb_id(&self) -> Option<FbId> {
|
||||
for i in 0..Self::FB_MAX {
|
||||
if self.inner.read().registered_fbs[i].is_none() {
|
||||
return Some(FbId::new(i as u32));
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
/// 抽象的帧缓冲区设备
|
||||
///
|
||||
/// 对应于`/sys/class/graphics/fb(x)`目录下的设备, 其中`(x)`为帧缓冲区的id
|
||||
///
|
||||
/// 该设备的父设备为真实的帧缓冲区设备
|
||||
#[derive(Debug)]
|
||||
#[cast_to([sync] Device)]
|
||||
pub struct FbDevice {
|
||||
inner: SpinLock<InnerFbDevice>,
|
||||
kobj_state: LockedKObjectState,
|
||||
}
|
||||
|
||||
impl FbDevice {
|
||||
pub const BASENAME: &'static str = "fb";
|
||||
fn new(fb: Weak<dyn FrameBuffer>, id: FbId) -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
inner: SpinLock::new(InnerFbDevice {
|
||||
fb,
|
||||
kern_inode: None,
|
||||
parent: None,
|
||||
kset: None,
|
||||
ktype: None,
|
||||
fb_id: id,
|
||||
}),
|
||||
kobj_state: LockedKObjectState::new(None),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn framebuffer(&self) -> Option<Arc<dyn FrameBuffer>> {
|
||||
self.inner.lock().fb.upgrade()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InnerFbDevice {
|
||||
fb: Weak<dyn FrameBuffer>,
|
||||
kern_inode: Option<Arc<KernFSInode>>,
|
||||
parent: Option<Weak<dyn KObject>>,
|
||||
kset: Option<Arc<KSet>>,
|
||||
ktype: Option<&'static dyn KObjType>,
|
||||
/// 帧缓冲区id
|
||||
fb_id: FbId,
|
||||
}
|
||||
|
||||
impl KObject for FbDevice {
|
||||
fn as_any_ref(&self) -> &dyn core::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn set_inode(&self, inode: Option<Arc<KernFSInode>>) {
|
||||
self.inner.lock().kern_inode = inode;
|
||||
}
|
||||
|
||||
fn inode(&self) -> Option<Arc<KernFSInode>> {
|
||||
self.inner.lock().kern_inode.clone()
|
||||
}
|
||||
|
||||
fn parent(&self) -> Option<Weak<dyn KObject>> {
|
||||
self.inner.lock().parent.clone()
|
||||
}
|
||||
|
||||
fn set_parent(&self, parent: Option<Weak<dyn KObject>>) {
|
||||
self.inner.lock().parent = parent;
|
||||
}
|
||||
|
||||
fn kset(&self) -> Option<Arc<KSet>> {
|
||||
self.inner.lock().kset.clone()
|
||||
}
|
||||
|
||||
fn set_kset(&self, kset: Option<Arc<KSet>>) {
|
||||
self.inner.lock().kset = kset;
|
||||
}
|
||||
|
||||
fn kobj_type(&self) -> Option<&'static dyn KObjType> {
|
||||
self.inner.lock().ktype
|
||||
}
|
||||
|
||||
fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) {
|
||||
self.inner.lock().ktype = ktype;
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
format!("{}{}", Self::BASENAME, self.inner.lock().fb_id.data())
|
||||
}
|
||||
|
||||
fn set_name(&self, _name: String) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
fn kobj_state(&self) -> RwLockReadGuard<KObjectState> {
|
||||
self.kobj_state.read()
|
||||
}
|
||||
|
||||
fn kobj_state_mut(&self) -> RwLockWriteGuard<KObjectState> {
|
||||
self.kobj_state.write()
|
||||
}
|
||||
|
||||
fn set_kobj_state(&self, state: KObjectState) {
|
||||
*self.kobj_state.write() = state;
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for FbDevice {
|
||||
fn dev_type(&self) -> DeviceType {
|
||||
DeviceType::Char
|
||||
}
|
||||
|
||||
fn id_table(&self) -> IdTable {
|
||||
IdTable::new(
|
||||
Self::BASENAME.to_string(),
|
||||
Some(DeviceNumber::new(
|
||||
Major::FB_MAJOR,
|
||||
self.inner.lock().fb_id.data(),
|
||||
)),
|
||||
)
|
||||
}
|
||||
|
||||
fn set_bus(&self, _bus: Option<Weak<dyn Bus>>) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn class(&self) -> Option<Arc<dyn Class>> {
|
||||
sys_class_graphics_instance().map(|ins| ins.clone() as Arc<dyn Class>)
|
||||
}
|
||||
fn set_class(&self, _class: Option<Arc<dyn Class>>) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
fn driver(&self) -> Option<Arc<dyn Driver>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn set_driver(&self, _driver: Option<Weak<dyn Driver>>) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
fn is_dead(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn can_match(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn set_can_match(&self, _can_match: bool) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
fn state_synced(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> {
|
||||
Some(&[&FbDeviceAttrGroup])
|
||||
}
|
||||
}
|
||||
|
320
kernel/src/driver/video/fbdev/base/fbsysfs.rs
Normal file
320
kernel/src/driver/video/fbdev/base/fbsysfs.rs
Normal file
@ -0,0 +1,320 @@
|
||||
use alloc::sync::Arc;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
driver::base::kobject::KObject,
|
||||
filesystem::{
|
||||
sysfs::{file::sysfs_emit_str, Attribute, AttributeGroup, SysFSOpsSupport},
|
||||
vfs::syscall::ModeType,
|
||||
},
|
||||
};
|
||||
|
||||
use super::fbmem::FbDevice;
|
||||
|
||||
/// 为FbDevice实现的sysfs属性组
|
||||
#[derive(Debug)]
|
||||
pub struct FbDeviceAttrGroup;
|
||||
|
||||
impl AttributeGroup for FbDeviceAttrGroup {
|
||||
fn name(&self) -> Option<&str> {
|
||||
None
|
||||
}
|
||||
|
||||
fn attrs(&self) -> &[&'static dyn Attribute] {
|
||||
&[
|
||||
&AttrBitsPerPixel,
|
||||
&AttrBlank,
|
||||
&AttrMode,
|
||||
&AttrModes,
|
||||
&AttrName,
|
||||
&AttrPan,
|
||||
&AttrRotate,
|
||||
&AttrState,
|
||||
&AttrStride,
|
||||
&AttrVirtualSize,
|
||||
]
|
||||
}
|
||||
|
||||
fn is_visible(
|
||||
&self,
|
||||
_kobj: alloc::sync::Arc<dyn KObject>,
|
||||
_attr: &'static dyn Attribute,
|
||||
) -> Option<ModeType> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AttrName;
|
||||
|
||||
impl Attribute for AttrName {
|
||||
fn name(&self) -> &str {
|
||||
"name"
|
||||
}
|
||||
|
||||
fn mode(&self) -> ModeType {
|
||||
ModeType::S_IRUGO
|
||||
}
|
||||
|
||||
fn support(&self) -> SysFSOpsSupport {
|
||||
SysFSOpsSupport::SHOW
|
||||
}
|
||||
|
||||
fn show(&self, kobj: Arc<dyn KObject>, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let fb_dev = kobj.arc_any().downcast::<FbDevice>().unwrap();
|
||||
let fb = fb_dev.framebuffer().ok_or(SystemError::ENODEV)?;
|
||||
let name = fb.name();
|
||||
return sysfs_emit_str(buf, &format!("{}\n", name));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AttrBitsPerPixel;
|
||||
|
||||
impl Attribute for AttrBitsPerPixel {
|
||||
fn name(&self) -> &str {
|
||||
"bits_per_pixel"
|
||||
}
|
||||
|
||||
fn mode(&self) -> ModeType {
|
||||
ModeType::S_IRUGO | ModeType::S_IWUSR
|
||||
}
|
||||
|
||||
fn support(&self) -> SysFSOpsSupport {
|
||||
SysFSOpsSupport::SHOW | SysFSOpsSupport::STORE
|
||||
}
|
||||
|
||||
fn store(&self, _kobj: Arc<dyn KObject>, _buf: &[u8]) -> Result<usize, SystemError> {
|
||||
kwarn!("attr bits_per_pixel store not implemented");
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
|
||||
fn show(&self, kobj: Arc<dyn KObject>, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let fb_dev = kobj.arc_any().downcast::<FbDevice>().unwrap();
|
||||
let fb = fb_dev.framebuffer().ok_or(SystemError::ENODEV)?;
|
||||
let bits_per_pixel = fb.current_fb_var().bits_per_pixel;
|
||||
return sysfs_emit_str(buf, &format!("{}\n", bits_per_pixel));
|
||||
}
|
||||
}
|
||||
|
||||
/// 用于清空屏幕的属性
|
||||
#[derive(Debug)]
|
||||
struct AttrBlank;
|
||||
|
||||
impl Attribute for AttrBlank {
|
||||
fn name(&self) -> &str {
|
||||
"blank"
|
||||
}
|
||||
|
||||
fn mode(&self) -> ModeType {
|
||||
ModeType::S_IWUSR
|
||||
}
|
||||
|
||||
fn support(&self) -> SysFSOpsSupport {
|
||||
SysFSOpsSupport::STORE
|
||||
}
|
||||
|
||||
// todo: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/video/fbdev/core/fbsysfs.c#309
|
||||
fn store(&self, _kobj: Arc<dyn KObject>, _buf: &[u8]) -> Result<usize, SystemError> {
|
||||
kwarn!("attr blank store not implemented");
|
||||
return Err(SystemError::ENOSYS);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AttrMode;
|
||||
|
||||
impl Attribute for AttrMode {
|
||||
fn name(&self) -> &str {
|
||||
"mode"
|
||||
}
|
||||
|
||||
fn mode(&self) -> ModeType {
|
||||
ModeType::S_IRUGO | ModeType::S_IWUSR
|
||||
}
|
||||
|
||||
fn support(&self) -> SysFSOpsSupport {
|
||||
SysFSOpsSupport::SHOW | SysFSOpsSupport::STORE
|
||||
}
|
||||
|
||||
/// https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/video/fbdev/core/fbsysfs.c#166
|
||||
fn show(&self, _kobj: Arc<dyn KObject>, _buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
todo!("AttrMode::show")
|
||||
}
|
||||
|
||||
/// https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/video/fbdev/core/fbsysfs.c#135
|
||||
fn store(&self, _kobj: Arc<dyn KObject>, _buf: &[u8]) -> Result<usize, SystemError> {
|
||||
todo!("AttrMode::store")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AttrModes;
|
||||
|
||||
impl Attribute for AttrModes {
|
||||
fn name(&self) -> &str {
|
||||
"modes"
|
||||
}
|
||||
|
||||
fn mode(&self) -> ModeType {
|
||||
ModeType::S_IRUGO | ModeType::S_IWUSR
|
||||
}
|
||||
|
||||
fn support(&self) -> SysFSOpsSupport {
|
||||
SysFSOpsSupport::SHOW | SysFSOpsSupport::STORE
|
||||
}
|
||||
|
||||
/// https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/video/fbdev/core/fbsysfs.c#206
|
||||
fn show(&self, _kobj: Arc<dyn KObject>, _buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
todo!("AttrMode::show")
|
||||
}
|
||||
|
||||
/// https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/video/fbdev/core/fbsysfs.c#177
|
||||
fn store(&self, _kobj: Arc<dyn KObject>, _buf: &[u8]) -> Result<usize, SystemError> {
|
||||
todo!("AttrMode::store")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AttrPan;
|
||||
|
||||
impl Attribute for AttrPan {
|
||||
fn name(&self) -> &str {
|
||||
"pan"
|
||||
}
|
||||
|
||||
fn mode(&self) -> ModeType {
|
||||
ModeType::S_IRUGO | ModeType::S_IWUSR
|
||||
}
|
||||
|
||||
fn support(&self) -> SysFSOpsSupport {
|
||||
SysFSOpsSupport::SHOW | SysFSOpsSupport::STORE
|
||||
}
|
||||
|
||||
fn show(&self, kobj: Arc<dyn KObject>, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let fb_dev = kobj.arc_any().downcast::<FbDevice>().unwrap();
|
||||
let fb = fb_dev.framebuffer().ok_or(SystemError::ENODEV)?;
|
||||
let var_info = fb.current_fb_var();
|
||||
return sysfs_emit_str(buf, &format!("{},{}\n", var_info.xoffset, var_info.yoffset));
|
||||
}
|
||||
|
||||
/// https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/video/fbdev/core/fbsysfs.c#365
|
||||
fn store(&self, _kobj: Arc<dyn KObject>, _buf: &[u8]) -> Result<usize, SystemError> {
|
||||
todo!("AttrPan::store")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AttrVirtualSize;
|
||||
|
||||
impl Attribute for AttrVirtualSize {
|
||||
fn name(&self) -> &str {
|
||||
"virtual_size"
|
||||
}
|
||||
|
||||
fn mode(&self) -> ModeType {
|
||||
ModeType::S_IRUGO | ModeType::S_IWUSR
|
||||
}
|
||||
|
||||
fn support(&self) -> SysFSOpsSupport {
|
||||
SysFSOpsSupport::SHOW | SysFSOpsSupport::STORE
|
||||
}
|
||||
|
||||
fn show(&self, kobj: Arc<dyn KObject>, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let fb_dev = kobj.arc_any().downcast::<FbDevice>().unwrap();
|
||||
let fb = fb_dev.framebuffer().ok_or(SystemError::ENODEV)?;
|
||||
let var_info = fb.current_fb_var();
|
||||
return sysfs_emit_str(
|
||||
buf,
|
||||
&format!("{},{}\n", var_info.xres_virtual, var_info.yres_virtual),
|
||||
);
|
||||
}
|
||||
|
||||
/// https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/video/fbdev/core/fbsysfs.c#273
|
||||
fn store(&self, _kobj: Arc<dyn KObject>, _buf: &[u8]) -> Result<usize, SystemError> {
|
||||
todo!("AttrVirtualSize::store")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AttrStride;
|
||||
|
||||
impl Attribute for AttrStride {
|
||||
fn name(&self) -> &str {
|
||||
"stride"
|
||||
}
|
||||
|
||||
fn mode(&self) -> ModeType {
|
||||
ModeType::S_IRUGO
|
||||
}
|
||||
|
||||
fn support(&self) -> SysFSOpsSupport {
|
||||
SysFSOpsSupport::SHOW
|
||||
}
|
||||
|
||||
fn show(&self, kobj: Arc<dyn KObject>, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let fb_dev = kobj.arc_any().downcast::<FbDevice>().unwrap();
|
||||
let fb = fb_dev.framebuffer().ok_or(SystemError::ENODEV)?;
|
||||
let fix_info = fb.current_fb_fix();
|
||||
return sysfs_emit_str(buf, &format!("{}\n", fix_info.line_length));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AttrRotate;
|
||||
|
||||
impl Attribute for AttrRotate {
|
||||
fn name(&self) -> &str {
|
||||
"rotate"
|
||||
}
|
||||
|
||||
fn mode(&self) -> ModeType {
|
||||
ModeType::S_IRUGO | ModeType::S_IWUSR
|
||||
}
|
||||
|
||||
fn support(&self) -> SysFSOpsSupport {
|
||||
SysFSOpsSupport::SHOW | SysFSOpsSupport::STORE
|
||||
}
|
||||
|
||||
fn show(&self, kobj: Arc<dyn KObject>, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let fb_dev = kobj.arc_any().downcast::<FbDevice>().unwrap();
|
||||
let fb = fb_dev.framebuffer().ok_or(SystemError::ENODEV)?;
|
||||
let var_info = fb.current_fb_var();
|
||||
|
||||
return sysfs_emit_str(buf, &format!("{}\n", var_info.rotate_angle));
|
||||
}
|
||||
|
||||
/// todo https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/video/fbdev/core/fbsysfs.c#246
|
||||
fn store(&self, _kobj: Arc<dyn KObject>, _buf: &[u8]) -> Result<usize, SystemError> {
|
||||
todo!("AttrRotate::store")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AttrState;
|
||||
|
||||
impl Attribute for AttrState {
|
||||
fn name(&self) -> &str {
|
||||
"state"
|
||||
}
|
||||
|
||||
fn mode(&self) -> ModeType {
|
||||
ModeType::S_IRUGO | ModeType::S_IWUSR
|
||||
}
|
||||
|
||||
fn support(&self) -> SysFSOpsSupport {
|
||||
SysFSOpsSupport::SHOW | SysFSOpsSupport::STORE
|
||||
}
|
||||
|
||||
fn show(&self, kobj: Arc<dyn KObject>, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let fb_dev = kobj.arc_any().downcast::<FbDevice>().unwrap();
|
||||
let fb = fb_dev.framebuffer().ok_or(SystemError::ENODEV)?;
|
||||
|
||||
return sysfs_emit_str(buf, &format!("{}\n", fb.state() as u8));
|
||||
}
|
||||
|
||||
/// todo https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/video/fbdev/core/fbsysfs.c#406
|
||||
fn store(&self, _kobj: Arc<dyn KObject>, _buf: &[u8]) -> Result<usize, SystemError> {
|
||||
todo!("AttrState::store")
|
||||
}
|
||||
}
|
@ -3,14 +3,41 @@ use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
driver::base::device::Device,
|
||||
mm::{ucontext::LockedVMA, PhysAddr},
|
||||
mm::{ucontext::LockedVMA, PhysAddr, VirtAddr},
|
||||
};
|
||||
|
||||
use self::fbmem::{FbDevice, FrameBufferManager};
|
||||
|
||||
pub mod fbcon;
|
||||
pub mod fbmem;
|
||||
pub mod fbsysfs;
|
||||
pub mod modedb;
|
||||
|
||||
// 帧缓冲区id
|
||||
int_like!(FbId, u32);
|
||||
|
||||
impl FbId {
|
||||
/// 帧缓冲区id的初始值(无效值)
|
||||
pub const INIT: Self = Self::new(u32::MAX);
|
||||
|
||||
/// 判断是否为无效的帧缓冲区id
|
||||
#[allow(dead_code)]
|
||||
pub const fn is_valid(&self) -> bool {
|
||||
if self.0 == Self::INIT.0 || self.0 >= FrameBufferManager::FB_MAX as u32 {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// 帧缓冲区应该实现的接口
|
||||
pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device {}
|
||||
pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device {
|
||||
/// 获取帧缓冲区的id
|
||||
fn fb_id(&self) -> FbId;
|
||||
|
||||
/// 设置帧缓冲区的id
|
||||
fn set_fb_id(&self, id: FbId);
|
||||
}
|
||||
|
||||
/// 帧缓冲区信息
|
||||
pub trait FrameBufferInfo {
|
||||
@ -18,19 +45,22 @@ pub trait FrameBufferInfo {
|
||||
fn screen_size(&self) -> usize;
|
||||
|
||||
/// 获取当前的可变帧缓冲信息
|
||||
fn current_fb_var(&self) -> &FbVarScreenInfo;
|
||||
|
||||
/// 获取当前的可变帧缓冲信息(可变引用)
|
||||
fn current_fb_var_mut(&mut self) -> &mut FbVarScreenInfo;
|
||||
fn current_fb_var(&self) -> FbVarScreenInfo;
|
||||
|
||||
/// 获取当前的固定帧缓冲信息
|
||||
fn current_fb_fix(&self) -> &FixedScreenInfo;
|
||||
|
||||
/// 获取当前的固定帧缓冲信息(可变引用)
|
||||
fn current_fb_fix_mut(&mut self) -> &mut FixedScreenInfo;
|
||||
fn current_fb_fix(&self) -> FixedScreenInfo;
|
||||
|
||||
/// 获取当前的视频模式
|
||||
fn video_mode(&self) -> Option<&FbVideoMode>;
|
||||
|
||||
/// 获取当前帧缓冲区对应的`/sys/class/graphics/fb0`或者`/sys/class/graphics/fb1`等的设备结构体
|
||||
fn fb_device(&self) -> Option<Arc<FbDevice>>;
|
||||
|
||||
/// 设置当前帧缓冲区对应的`/sys/class/graphics/fb0`或者`/sys/class/graphics/fb1`等的设备结构体
|
||||
fn set_fb_device(&self, device: Option<Arc<FbDevice>>);
|
||||
|
||||
/// 获取帧缓冲区的状态
|
||||
fn state(&self) -> FbState;
|
||||
}
|
||||
|
||||
/// 帧缓冲区操作
|
||||
@ -94,6 +124,13 @@ pub trait FrameBufferOps {
|
||||
fn fb_destroy(&self);
|
||||
}
|
||||
|
||||
/// 帧缓冲区的状态
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum FbState {
|
||||
Running = 0,
|
||||
Suspended = 1,
|
||||
}
|
||||
|
||||
/// 屏幕黑屏模式。
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
@ -221,10 +258,10 @@ pub struct FbVarScreenInfo {
|
||||
pub pixel_format: FbPixelFormat,
|
||||
/// 激活标志(参见FB_ACTIVATE_*)
|
||||
pub activate: FbActivateFlags,
|
||||
/// 帧缓冲区的高度(像素)
|
||||
pub height: u32,
|
||||
/// 帧缓冲区的宽度(像素)
|
||||
pub width: u32,
|
||||
/// 帧缓冲区的高度(像素) None表示未知
|
||||
pub height: Option<u32>,
|
||||
/// 帧缓冲区的宽度(像素) None表示未知
|
||||
pub width: Option<u32>,
|
||||
/// 像素时钟(皮秒)
|
||||
pub pixclock: u32,
|
||||
/// 左边距
|
||||
@ -249,6 +286,43 @@ pub struct FbVarScreenInfo {
|
||||
pub colorspace: V4l2Colorspace,
|
||||
}
|
||||
|
||||
impl Default for FbVarScreenInfo {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
xres: Default::default(),
|
||||
yres: Default::default(),
|
||||
xres_virtual: Default::default(),
|
||||
yres_virtual: Default::default(),
|
||||
xoffset: Default::default(),
|
||||
yoffset: Default::default(),
|
||||
bits_per_pixel: Default::default(),
|
||||
color_mode: Default::default(),
|
||||
red: Default::default(),
|
||||
green: Default::default(),
|
||||
blue: Default::default(),
|
||||
transp: Default::default(),
|
||||
pixel_format: Default::default(),
|
||||
activate: Default::default(),
|
||||
height: None,
|
||||
width: None,
|
||||
pixclock: Default::default(),
|
||||
left_margin: Default::default(),
|
||||
right_margin: Default::default(),
|
||||
upper_margin: Default::default(),
|
||||
lower_margin: Default::default(),
|
||||
hsync_len: Default::default(),
|
||||
vsync_len: Default::default(),
|
||||
sync: FbSyncFlags::empty(),
|
||||
vmode: FbVModeFlags::empty(),
|
||||
rotate_angle: Default::default(),
|
||||
colorspace: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 帧缓冲区的颜色模式
|
||||
///
|
||||
/// 默认为彩色
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum FbColorMode {
|
||||
@ -260,6 +334,12 @@ pub enum FbColorMode {
|
||||
FourCC,
|
||||
}
|
||||
|
||||
impl Default for FbColorMode {
|
||||
fn default() -> Self {
|
||||
FbColorMode::Color
|
||||
}
|
||||
}
|
||||
|
||||
/// `FbBitfield` 结构体用于描述颜色字段的位域。
|
||||
///
|
||||
/// 所有的偏移量都是从右边开始,位于一个精确为'bits_per_pixel'宽度的"像素"值内。
|
||||
@ -289,6 +369,16 @@ impl FbBitfield {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FbBitfield {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
offset: Default::default(),
|
||||
length: Default::default(),
|
||||
msb_right: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// `FbActivateFlags` 用于描述帧缓冲区的激活标志。
|
||||
///
|
||||
@ -317,6 +407,12 @@ bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FbActivateFlags {
|
||||
fn default() -> Self {
|
||||
FbActivateFlags::FB_ACTIVATE_NOW
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum FbPixelFormat {
|
||||
@ -327,6 +423,12 @@ pub enum FbPixelFormat {
|
||||
Reserved,
|
||||
}
|
||||
|
||||
impl Default for FbPixelFormat {
|
||||
fn default() -> Self {
|
||||
FbPixelFormat::Standard
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct FbSyncFlags: u32 {
|
||||
/// 水平同步高电平有效
|
||||
@ -415,9 +517,9 @@ pub struct FixedScreenInfo {
|
||||
// 字符串,用于标识屏幕,例如 "TT Builtin"
|
||||
pub id: [char; 16],
|
||||
// 帧缓冲区的起始物理地址
|
||||
pub smem_start: PhysAddr,
|
||||
pub smem_start: Option<PhysAddr>,
|
||||
// 帧缓冲区的长度
|
||||
pub smem_len: u32,
|
||||
pub smem_len: usize,
|
||||
// 屏幕类型,参考 FB_TYPE_
|
||||
pub fb_type: FbType,
|
||||
// 用于表示交错平面的小端辅助类型
|
||||
@ -432,16 +534,61 @@ pub struct FixedScreenInfo {
|
||||
pub ywrapstep: u16,
|
||||
// 一行的大小(以字节为单位)
|
||||
pub line_length: u32,
|
||||
// 内存映射I/O的起始物理地址
|
||||
pub mmio_start: PhysAddr,
|
||||
// 内存映射I/O端口的起始物理地址
|
||||
pub mmio_start: Option<PhysAddr>,
|
||||
// 内存映射I/O的长度
|
||||
pub mmio_len: u32,
|
||||
pub mmio_len: usize,
|
||||
// 表示驱动器拥有的特定芯片/卡片类型
|
||||
pub accel: u32,
|
||||
pub accel: FbAccel,
|
||||
// 表示支持的特性,参考 FB_CAP_
|
||||
pub capabilities: FbCapability,
|
||||
}
|
||||
|
||||
impl FixedScreenInfo {
|
||||
/// 将字符串转换为长度为16的字符数组(包含结尾的`\0`)
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `name`: 字符串,长度不超过15,超过的部分将被截断
|
||||
///
|
||||
/// ## 返回
|
||||
///
|
||||
/// 长度为16的字符数组
|
||||
pub const fn name2id(name: &str) -> [char; 16] {
|
||||
let mut id = [0 as char; 16];
|
||||
let mut i = 0;
|
||||
|
||||
while i < 15 && i < name.len() {
|
||||
id[i] = name.as_bytes()[i] as char;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
id[i] = '\0';
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FixedScreenInfo {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
id: Default::default(),
|
||||
smem_start: None,
|
||||
smem_len: Default::default(),
|
||||
fb_type: FbType::PackedPixels,
|
||||
type_aux: Default::default(),
|
||||
visual: FbVisual::Mono10,
|
||||
xpanstep: Default::default(),
|
||||
ypanstep: Default::default(),
|
||||
ywrapstep: Default::default(),
|
||||
line_length: Default::default(),
|
||||
mmio_start: None,
|
||||
mmio_len: Default::default(),
|
||||
accel: Default::default(),
|
||||
capabilities: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 帧缓冲类型
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
@ -488,6 +635,12 @@ pub enum FbCapability {
|
||||
FourCC,
|
||||
}
|
||||
|
||||
impl Default for FbCapability {
|
||||
fn default() -> Self {
|
||||
FbCapability::Default
|
||||
}
|
||||
}
|
||||
|
||||
/// 视频模式
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
@ -521,3 +674,179 @@ pub struct FbVideoMode {
|
||||
/// 标志
|
||||
pub flag: u32,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum FbAccel {
|
||||
/// 没有硬件加速器
|
||||
None,
|
||||
|
||||
AtariBlitter = 1,
|
||||
AmigaBlitter = 2,
|
||||
S3Trio64 = 3,
|
||||
NCR77C32BLT = 4,
|
||||
S3Virge = 5,
|
||||
AtiMach64GX = 6,
|
||||
DECTGA = 7,
|
||||
AtiMach64CT = 8,
|
||||
AtiMach64VT = 9,
|
||||
AtiMach64GT = 10,
|
||||
SunCreator = 11,
|
||||
SunCGSix = 12,
|
||||
SunLeo = 13,
|
||||
IMSTwinTurbo = 14,
|
||||
Acc3DLabsPermedia2 = 15,
|
||||
MatroxMGA2064W = 16,
|
||||
MatroxMGA1064SG = 17,
|
||||
MatroxMGA2164W = 18,
|
||||
MatroxMGA2164WAGP = 19,
|
||||
MatroxMGAG400 = 20,
|
||||
NV3 = 21,
|
||||
NV4 = 22,
|
||||
NV5 = 23,
|
||||
NV6 = 24,
|
||||
XGIVolariV = 25,
|
||||
XGIVolariZ = 26,
|
||||
Omap1610 = 27,
|
||||
TridentTGUI = 28,
|
||||
Trident3DImage = 29,
|
||||
TridentBlade3D = 30,
|
||||
TridentBladeXP = 31,
|
||||
CirrusAlpine = 32,
|
||||
NeoMagicNM2070 = 90,
|
||||
NeoMagicNM2090 = 91,
|
||||
NeoMagicNM2093 = 92,
|
||||
NeoMagicNM2097 = 93,
|
||||
NeoMagicNM2160 = 94,
|
||||
NeoMagicNM2200 = 95,
|
||||
NeoMagicNM2230 = 96,
|
||||
NeoMagicNM2360 = 97,
|
||||
NeoMagicNM2380 = 98,
|
||||
PXA3XX = 99,
|
||||
|
||||
Savage4 = 0x80,
|
||||
Savage3D = 0x81,
|
||||
Savage3DMV = 0x82,
|
||||
Savage2000 = 0x83,
|
||||
SavageMXMV = 0x84,
|
||||
SavageMX = 0x85,
|
||||
SavageIXMV = 0x86,
|
||||
SavageIX = 0x87,
|
||||
ProSavagePM = 0x88,
|
||||
ProSavageKM = 0x89,
|
||||
S3Twister = 0x8a,
|
||||
S3TwisterK = 0x8b,
|
||||
SuperSavage = 0x8c,
|
||||
ProSavageDDR = 0x8d,
|
||||
ProSavageDDRK = 0x8e,
|
||||
// Add other accelerators here
|
||||
}
|
||||
|
||||
impl Default for FbAccel {
|
||||
fn default() -> Self {
|
||||
FbAccel::None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct BootTimeScreenInfo {
|
||||
pub origin_x: u8,
|
||||
pub origin_y: u8,
|
||||
/// text mode时,每行的字符数
|
||||
pub origin_video_cols: u8,
|
||||
/// text mode时,行数
|
||||
pub origin_video_lines: u8,
|
||||
/// 标记屏幕是否为VGA类型
|
||||
pub is_vga: bool,
|
||||
/// video mode type
|
||||
pub video_type: BootTimeVideoType,
|
||||
|
||||
// 以下字段用于线性帧缓冲区
|
||||
/// 线性帧缓冲区的起始物理地址
|
||||
pub lfb_base: PhysAddr,
|
||||
/// 线性帧缓冲区在初始化阶段被映射到的起始虚拟地址
|
||||
///
|
||||
/// 这个值可能会被设置2次:
|
||||
///
|
||||
/// - 内存管理初始化之前,early init阶段,临时映射
|
||||
/// - 内存管理初始化完毕,重新映射时被设置
|
||||
pub lfb_virt_base: Option<VirtAddr>,
|
||||
/// 线性帧缓冲区的长度
|
||||
pub lfb_size: usize,
|
||||
/// 线性帧缓冲区的宽度(像素)
|
||||
pub lfb_width: u32,
|
||||
/// 线性帧缓冲区的高度(像素)
|
||||
pub lfb_height: u32,
|
||||
/// 线性帧缓冲区的深度(位数)
|
||||
pub lfb_depth: u8,
|
||||
/// 红色位域的大小
|
||||
pub red_size: u8,
|
||||
/// 红色位域的偏移量(左移位数)
|
||||
pub red_pos: u8,
|
||||
/// 绿色位域的大小
|
||||
pub green_size: u8,
|
||||
/// 绿色位域的偏移量(左移位数)
|
||||
pub green_pos: u8,
|
||||
/// 蓝色位域的大小
|
||||
pub blue_size: u8,
|
||||
/// 蓝色位域的偏移量(左移位数)
|
||||
pub blue_pos: u8,
|
||||
}
|
||||
|
||||
impl BootTimeScreenInfo {
|
||||
pub const DEFAULT: Self = Self {
|
||||
origin_x: 0,
|
||||
origin_y: 0,
|
||||
is_vga: false,
|
||||
lfb_base: PhysAddr::new(0),
|
||||
lfb_size: 0,
|
||||
lfb_width: 0,
|
||||
lfb_height: 0,
|
||||
red_size: 0,
|
||||
red_pos: 0,
|
||||
green_size: 0,
|
||||
green_pos: 0,
|
||||
blue_size: 0,
|
||||
blue_pos: 0,
|
||||
video_type: BootTimeVideoType::UnDefined,
|
||||
origin_video_cols: 0,
|
||||
origin_video_lines: 0,
|
||||
lfb_virt_base: None,
|
||||
lfb_depth: 0,
|
||||
};
|
||||
}
|
||||
|
||||
/// Video types for different display hardware
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub enum BootTimeVideoType {
|
||||
UnDefined,
|
||||
/// Monochrome Text Display
|
||||
Mda,
|
||||
/// CGA Display
|
||||
Cga,
|
||||
/// EGA/VGA in Monochrome Mode
|
||||
EgaM,
|
||||
/// EGA in Color Mode
|
||||
EgaC,
|
||||
/// VGA+ in Color Mode
|
||||
VgaC,
|
||||
/// VESA VGA in graphic mode
|
||||
Vlfb,
|
||||
/// ACER PICA-61 local S3 video
|
||||
PicaS3,
|
||||
/// MIPS Magnum 4000 G364 video
|
||||
MipsG364,
|
||||
/// Various SGI graphics hardware
|
||||
Sgi,
|
||||
/// DEC TGA
|
||||
TgaC,
|
||||
/// Sun frame buffer
|
||||
Sun,
|
||||
/// Sun PCI based frame buffer
|
||||
SunPci,
|
||||
/// PowerMacintosh frame buffer
|
||||
Pmac,
|
||||
/// EFI graphic mode
|
||||
Efi,
|
||||
}
|
||||
|
3
kernel/src/driver/video/fbdev/base/modedb.rs
Normal file
3
kernel/src/driver/video/fbdev/base/modedb.rs
Normal file
@ -0,0 +1,3 @@
|
||||
//! todo: 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/video/fbdev/core/modedb.c
|
||||
//!
|
||||
//! 实现modedb
|
@ -1 +1,2 @@
|
||||
pub mod base;
|
||||
pub mod vesafb;
|
||||
|
680
kernel/src/driver/video/fbdev/vesafb.rs
Normal file
680
kernel/src/driver/video/fbdev/vesafb.rs
Normal file
@ -0,0 +1,680 @@
|
||||
use core::{
|
||||
ffi::{c_uint, c_void},
|
||||
mem::MaybeUninit,
|
||||
sync::atomic::AtomicBool,
|
||||
};
|
||||
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use system_error::SystemError;
|
||||
use unified_init::macros::unified_init;
|
||||
|
||||
use crate::{
|
||||
arch::MMArch,
|
||||
driver::{
|
||||
base::{
|
||||
class::Class,
|
||||
device::{
|
||||
bus::Bus, device_manager, driver::Driver, Device, DeviceState, DeviceType, IdTable,
|
||||
},
|
||||
kobject::{KObjType, KObject, KObjectState, LockedKObjectState},
|
||||
kset::KSet,
|
||||
platform::{
|
||||
platform_device::{platform_device_manager, PlatformDevice},
|
||||
platform_driver::{platform_driver_manager, PlatformDriver},
|
||||
CompatibleTable,
|
||||
},
|
||||
},
|
||||
tty::serial::serial8250::send_to_default_serial8250_port,
|
||||
video::fbdev::base::{fbmem::frame_buffer_manager, FbVisual},
|
||||
},
|
||||
filesystem::{
|
||||
kernfs::KernFSInode,
|
||||
sysfs::{file::sysfs_emit_str, Attribute, AttributeGroup, SysFSOpsSupport},
|
||||
vfs::syscall::ModeType,
|
||||
},
|
||||
include::bindings::bindings::{
|
||||
multiboot2_get_Framebuffer_info, multiboot2_iter, multiboot_tag_framebuffer_info_t,
|
||||
},
|
||||
init::{boot_params, initcall::INITCALL_DEVICE},
|
||||
libs::{
|
||||
align::page_align_up,
|
||||
once::Once,
|
||||
rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
spinlock::SpinLock,
|
||||
},
|
||||
mm::{
|
||||
allocator::page_frame::PageFrameCount, no_init::pseudo_map_phys, MemoryManagementArch,
|
||||
PhysAddr, VirtAddr,
|
||||
},
|
||||
};
|
||||
|
||||
use super::base::{
|
||||
fbmem::FbDevice, BlankMode, BootTimeVideoType, FbAccel, FbActivateFlags, FbId, FbState, FbType,
|
||||
FbVModeFlags, FbVarScreenInfo, FbVideoMode, FixedScreenInfo, FrameBuffer, FrameBufferInfo,
|
||||
FrameBufferOps,
|
||||
};
|
||||
|
||||
/// 当前机器上面是否有vesa帧缓冲区
|
||||
static HAS_VESA_FB: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
lazy_static! {
|
||||
static ref VESAFB_FIX_INFO: RwLock<FixedScreenInfo> = RwLock::new(FixedScreenInfo {
|
||||
id: FixedScreenInfo::name2id("VESA VGA"),
|
||||
fb_type: FbType::PackedPixels,
|
||||
accel: FbAccel::None,
|
||||
..Default::default()
|
||||
});
|
||||
static ref VESAFB_DEFINED: RwLock<FbVarScreenInfo> = RwLock::new(FbVarScreenInfo {
|
||||
activate: FbActivateFlags::FB_ACTIVATE_NOW,
|
||||
height: None,
|
||||
width: None,
|
||||
right_margin: 32,
|
||||
upper_margin: 16,
|
||||
lower_margin: 4,
|
||||
vsync_len: 4,
|
||||
vmode: FbVModeFlags::FB_VMODE_NONINTERLACED,
|
||||
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cast_to([sync] Device)]
|
||||
#[cast_to([sync] PlatformDevice)]
|
||||
pub struct VesaFb {
|
||||
inner: SpinLock<InnerVesaFb>,
|
||||
kobj_state: LockedKObjectState,
|
||||
}
|
||||
|
||||
impl VesaFb {
|
||||
pub const NAME: &'static str = "vesa_vga";
|
||||
pub fn new() -> Self {
|
||||
return Self {
|
||||
inner: SpinLock::new(InnerVesaFb {
|
||||
bus: None,
|
||||
class: None,
|
||||
driver: None,
|
||||
kern_inode: None,
|
||||
parent: None,
|
||||
kset: None,
|
||||
kobj_type: None,
|
||||
device_state: DeviceState::NotInitialized,
|
||||
pdev_id: 0,
|
||||
pdev_id_auto: false,
|
||||
fb_id: FbId::INIT,
|
||||
fb_device: None,
|
||||
fb_state: FbState::Suspended,
|
||||
}),
|
||||
kobj_state: LockedKObjectState::new(None),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InnerVesaFb {
|
||||
bus: Option<Weak<dyn Bus>>,
|
||||
class: Option<Arc<dyn Class>>,
|
||||
driver: Option<Weak<dyn Driver>>,
|
||||
kern_inode: Option<Arc<KernFSInode>>,
|
||||
parent: Option<Weak<dyn KObject>>,
|
||||
kset: Option<Arc<KSet>>,
|
||||
kobj_type: Option<&'static dyn KObjType>,
|
||||
device_state: DeviceState,
|
||||
pdev_id: i32,
|
||||
pdev_id_auto: bool,
|
||||
fb_id: FbId,
|
||||
fb_device: Option<Arc<FbDevice>>,
|
||||
fb_state: FbState,
|
||||
}
|
||||
|
||||
impl FrameBuffer for VesaFb {
|
||||
fn fb_id(&self) -> FbId {
|
||||
self.inner.lock().fb_id
|
||||
}
|
||||
|
||||
fn set_fb_id(&self, id: FbId) {
|
||||
self.inner.lock().fb_id = id;
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformDevice for VesaFb {
|
||||
fn pdev_name(&self) -> &str {
|
||||
Self::NAME
|
||||
}
|
||||
|
||||
fn set_pdev_id(&self, id: i32) {
|
||||
self.inner.lock().pdev_id = id;
|
||||
}
|
||||
|
||||
fn set_pdev_id_auto(&self, id_auto: bool) {
|
||||
self.inner.lock().pdev_id_auto = id_auto;
|
||||
}
|
||||
|
||||
fn compatible_table(&self) -> CompatibleTable {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
self.inner.lock().device_state == DeviceState::Initialized
|
||||
}
|
||||
|
||||
fn set_state(&self, set_state: DeviceState) {
|
||||
self.inner.lock().device_state = set_state;
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for VesaFb {
|
||||
fn dev_type(&self) -> DeviceType {
|
||||
DeviceType::Char
|
||||
}
|
||||
|
||||
fn id_table(&self) -> IdTable {
|
||||
IdTable::new(self.name(), None)
|
||||
}
|
||||
|
||||
fn bus(&self) -> Option<Weak<dyn Bus>> {
|
||||
self.inner.lock().bus.clone()
|
||||
}
|
||||
|
||||
fn set_bus(&self, bus: Option<Weak<dyn Bus>>) {
|
||||
self.inner.lock().bus = bus;
|
||||
}
|
||||
|
||||
fn set_class(&self, class: Option<Arc<dyn Class>>) {
|
||||
self.inner.lock().class = class;
|
||||
}
|
||||
|
||||
fn driver(&self) -> Option<Arc<dyn Driver>> {
|
||||
self.inner.lock().driver.clone()?.upgrade()
|
||||
}
|
||||
|
||||
fn set_driver(&self, driver: Option<Weak<dyn Driver>>) {
|
||||
self.inner.lock().driver = driver;
|
||||
}
|
||||
|
||||
fn is_dead(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn can_match(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn set_can_match(&self, _can_match: bool) {}
|
||||
|
||||
fn state_synced(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl KObject for VesaFb {
|
||||
fn as_any_ref(&self) -> &dyn core::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn set_inode(&self, inode: Option<Arc<KernFSInode>>) {
|
||||
self.inner.lock().kern_inode = inode;
|
||||
}
|
||||
|
||||
fn inode(&self) -> Option<Arc<KernFSInode>> {
|
||||
self.inner.lock().kern_inode.clone()
|
||||
}
|
||||
|
||||
fn parent(&self) -> Option<Weak<dyn KObject>> {
|
||||
self.inner.lock().parent.clone()
|
||||
}
|
||||
|
||||
fn set_parent(&self, parent: Option<Weak<dyn KObject>>) {
|
||||
self.inner.lock().parent = parent;
|
||||
}
|
||||
|
||||
fn kset(&self) -> Option<Arc<KSet>> {
|
||||
self.inner.lock().kset.clone()
|
||||
}
|
||||
|
||||
fn set_kset(&self, kset: Option<Arc<KSet>>) {
|
||||
self.inner.lock().kset = kset;
|
||||
}
|
||||
|
||||
fn kobj_type(&self) -> Option<&'static dyn KObjType> {
|
||||
self.inner.lock().kobj_type
|
||||
}
|
||||
|
||||
fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) {
|
||||
self.inner.lock().kobj_type = ktype;
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
Self::NAME.to_string()
|
||||
}
|
||||
|
||||
fn set_name(&self, _name: String) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
fn kobj_state(&self) -> RwLockReadGuard<KObjectState> {
|
||||
self.kobj_state.read()
|
||||
}
|
||||
|
||||
fn kobj_state_mut(&self) -> RwLockWriteGuard<KObjectState> {
|
||||
self.kobj_state.write()
|
||||
}
|
||||
|
||||
fn set_kobj_state(&self, state: KObjectState) {
|
||||
*self.kobj_state.write() = state;
|
||||
}
|
||||
}
|
||||
|
||||
impl FrameBufferOps for VesaFb {
|
||||
fn fb_open(&self, _user: bool) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn fb_release(&self, _user: bool) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn fb_set_color_register(
|
||||
&self,
|
||||
_regno: u16,
|
||||
_red: u16,
|
||||
_green: u16,
|
||||
_blue: u16,
|
||||
) -> Result<(), SystemError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn fb_blank(&self, _blank_mode: BlankMode) -> Result<(), SystemError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn fb_destroy(&self) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl FrameBufferInfo for VesaFb {
|
||||
fn fb_device(&self) -> Option<Arc<FbDevice>> {
|
||||
self.inner.lock().fb_device.clone()
|
||||
}
|
||||
|
||||
fn set_fb_device(&self, device: Option<Arc<FbDevice>>) {
|
||||
self.inner.lock().fb_device = device;
|
||||
}
|
||||
|
||||
fn screen_size(&self) -> usize {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn current_fb_var(&self) -> FbVarScreenInfo {
|
||||
VESAFB_DEFINED.read().clone()
|
||||
}
|
||||
|
||||
fn current_fb_fix(&self) -> FixedScreenInfo {
|
||||
VESAFB_FIX_INFO.read().clone()
|
||||
}
|
||||
|
||||
fn video_mode(&self) -> Option<&FbVideoMode> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn state(&self) -> FbState {
|
||||
self.inner.lock().fb_state
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cast_to([sync] PlatformDriver)]
|
||||
struct VesaFbDriver {
|
||||
inner: SpinLock<InnerVesaFbDriver>,
|
||||
kobj_state: LockedKObjectState,
|
||||
}
|
||||
|
||||
impl VesaFbDriver {
|
||||
pub fn new() -> Arc<Self> {
|
||||
let r = Arc::new(Self {
|
||||
inner: SpinLock::new(InnerVesaFbDriver {
|
||||
ktype: None,
|
||||
kset: None,
|
||||
parent: None,
|
||||
kernfs_inode: None,
|
||||
devices: Vec::new(),
|
||||
bus: None,
|
||||
self_ref: Weak::new(),
|
||||
}),
|
||||
kobj_state: LockedKObjectState::new(None),
|
||||
});
|
||||
|
||||
r.inner.lock().self_ref = Arc::downgrade(&r);
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InnerVesaFbDriver {
|
||||
ktype: Option<&'static dyn KObjType>,
|
||||
kset: Option<Arc<KSet>>,
|
||||
parent: Option<Weak<dyn KObject>>,
|
||||
kernfs_inode: Option<Arc<KernFSInode>>,
|
||||
devices: Vec<Arc<dyn Device>>,
|
||||
bus: Option<Weak<dyn Bus>>,
|
||||
|
||||
self_ref: Weak<VesaFbDriver>,
|
||||
}
|
||||
|
||||
impl VesaFbDriver {
|
||||
const NAME: &'static str = "vesa-framebuffer";
|
||||
}
|
||||
|
||||
impl PlatformDriver for VesaFbDriver {
|
||||
fn probe(&self, device: &Arc<dyn PlatformDevice>) -> Result<(), SystemError> {
|
||||
let device = device
|
||||
.clone()
|
||||
.arc_any()
|
||||
.downcast::<VesaFb>()
|
||||
.map_err(|_| SystemError::EINVAL)?;
|
||||
|
||||
device.set_driver(Some(self.inner.lock_irqsave().self_ref.clone()));
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn remove(&self, _device: &Arc<dyn PlatformDevice>) -> Result<(), SystemError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn shutdown(&self, _device: &Arc<dyn PlatformDevice>) -> Result<(), SystemError> {
|
||||
// do nothing
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn suspend(&self, _device: &Arc<dyn PlatformDevice>) -> Result<(), SystemError> {
|
||||
// do nothing
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn resume(&self, _device: &Arc<dyn PlatformDevice>) -> Result<(), SystemError> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Driver for VesaFbDriver {
|
||||
fn id_table(&self) -> Option<IdTable> {
|
||||
Some(IdTable::new(VesaFb::NAME.to_string(), None))
|
||||
}
|
||||
|
||||
fn devices(&self) -> Vec<Arc<dyn Device>> {
|
||||
self.inner.lock().devices.clone()
|
||||
}
|
||||
|
||||
fn add_device(&self, device: Arc<dyn Device>) {
|
||||
let mut guard = self.inner.lock();
|
||||
// check if the device is already in the list
|
||||
if guard.devices.iter().any(|dev| Arc::ptr_eq(dev, &device)) {
|
||||
return;
|
||||
}
|
||||
|
||||
guard.devices.push(device);
|
||||
}
|
||||
|
||||
fn delete_device(&self, device: &Arc<dyn Device>) {
|
||||
let mut guard = self.inner.lock();
|
||||
guard.devices.retain(|dev| !Arc::ptr_eq(dev, device));
|
||||
}
|
||||
|
||||
fn set_bus(&self, bus: Option<Weak<dyn Bus>>) {
|
||||
self.inner.lock().bus = bus;
|
||||
}
|
||||
|
||||
fn bus(&self) -> Option<Weak<dyn Bus>> {
|
||||
self.inner.lock().bus.clone()
|
||||
}
|
||||
|
||||
fn dev_groups(&self) -> &'static [&'static dyn AttributeGroup] {
|
||||
return &[&VesaFbAnonAttributeGroup];
|
||||
}
|
||||
}
|
||||
|
||||
impl KObject for VesaFbDriver {
|
||||
fn as_any_ref(&self) -> &dyn core::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn set_inode(&self, inode: Option<Arc<KernFSInode>>) {
|
||||
self.inner.lock().kernfs_inode = inode;
|
||||
}
|
||||
|
||||
fn inode(&self) -> Option<Arc<KernFSInode>> {
|
||||
self.inner.lock().kernfs_inode.clone()
|
||||
}
|
||||
|
||||
fn parent(&self) -> Option<Weak<dyn KObject>> {
|
||||
self.inner.lock().parent.clone()
|
||||
}
|
||||
|
||||
fn set_parent(&self, parent: Option<Weak<dyn KObject>>) {
|
||||
self.inner.lock().parent = parent;
|
||||
}
|
||||
|
||||
fn kset(&self) -> Option<Arc<KSet>> {
|
||||
self.inner.lock().kset.clone()
|
||||
}
|
||||
|
||||
fn set_kset(&self, kset: Option<Arc<KSet>>) {
|
||||
self.inner.lock().kset = kset;
|
||||
}
|
||||
|
||||
fn kobj_type(&self) -> Option<&'static dyn KObjType> {
|
||||
self.inner.lock().ktype
|
||||
}
|
||||
|
||||
fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) {
|
||||
self.inner.lock().ktype = ktype;
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
Self::NAME.to_string()
|
||||
}
|
||||
|
||||
fn set_name(&self, _name: String) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
fn kobj_state(&self) -> RwLockReadGuard<KObjectState> {
|
||||
self.kobj_state.read()
|
||||
}
|
||||
|
||||
fn kobj_state_mut(&self) -> RwLockWriteGuard<KObjectState> {
|
||||
self.kobj_state.write()
|
||||
}
|
||||
|
||||
fn set_kobj_state(&self, state: KObjectState) {
|
||||
*self.kobj_state.write() = state;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct VesaFbAnonAttributeGroup;
|
||||
|
||||
impl AttributeGroup for VesaFbAnonAttributeGroup {
|
||||
fn name(&self) -> Option<&str> {
|
||||
None
|
||||
}
|
||||
|
||||
fn attrs(&self) -> &[&'static dyn Attribute] {
|
||||
&[&AnonAttrPhysAddr as &'static dyn Attribute]
|
||||
}
|
||||
|
||||
fn is_visible(
|
||||
&self,
|
||||
_kobj: Arc<dyn KObject>,
|
||||
attr: &'static dyn Attribute,
|
||||
) -> Option<ModeType> {
|
||||
Some(attr.mode())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AnonAttrPhysAddr;
|
||||
|
||||
impl Attribute for AnonAttrPhysAddr {
|
||||
fn name(&self) -> &str {
|
||||
"smem_start"
|
||||
}
|
||||
|
||||
fn mode(&self) -> ModeType {
|
||||
ModeType::S_IRUGO
|
||||
}
|
||||
|
||||
fn support(&self) -> SysFSOpsSupport {
|
||||
SysFSOpsSupport::SHOW
|
||||
}
|
||||
|
||||
fn show(&self, _kobj: Arc<dyn KObject>, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
sysfs_emit_str(
|
||||
buf,
|
||||
format!(
|
||||
"0x{:x}\n",
|
||||
VESAFB_FIX_INFO
|
||||
.read()
|
||||
.smem_start
|
||||
.unwrap_or(PhysAddr::new(0))
|
||||
.data()
|
||||
)
|
||||
.as_str(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[unified_init(INITCALL_DEVICE)]
|
||||
pub fn vesa_fb_driver_init() -> Result<(), SystemError> {
|
||||
let driver = VesaFbDriver::new();
|
||||
|
||||
platform_driver_manager().register(driver)?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 在内存管理初始化之前,初始化vesafb
|
||||
pub fn vesafb_early_init() -> Result<VirtAddr, SystemError> {
|
||||
let mut _reserved: u32 = 0;
|
||||
|
||||
let mut fb_info: MaybeUninit<multiboot_tag_framebuffer_info_t> = MaybeUninit::uninit();
|
||||
//从multiboot2中读取帧缓冲区信息至fb_info
|
||||
|
||||
// todo: 换成rust的,并且检测是否成功获取
|
||||
unsafe {
|
||||
multiboot2_iter(
|
||||
Some(multiboot2_get_Framebuffer_info),
|
||||
fb_info.as_mut_ptr() as usize as *mut c_void,
|
||||
&mut _reserved as *mut c_uint,
|
||||
)
|
||||
};
|
||||
unsafe { fb_info.assume_init() };
|
||||
let fb_info: multiboot_tag_framebuffer_info_t = unsafe { core::mem::transmute(fb_info) };
|
||||
|
||||
// todo: 判断是否有vesa帧缓冲区,这里暂时直接设置true
|
||||
HAS_VESA_FB.store(true, core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
let width = fb_info.framebuffer_width;
|
||||
let height = fb_info.framebuffer_height;
|
||||
|
||||
let mut boot_params_guard = boot_params().write();
|
||||
let boottime_screen_info = &mut boot_params_guard.screen_info;
|
||||
|
||||
boottime_screen_info.is_vga = true;
|
||||
|
||||
boottime_screen_info.lfb_base = PhysAddr::new(fb_info.framebuffer_addr as usize);
|
||||
|
||||
if fb_info.framebuffer_type == 2 {
|
||||
//当type=2时,width与height用字符数表示,故depth=8
|
||||
boottime_screen_info.origin_video_cols = width as u8;
|
||||
boottime_screen_info.origin_video_lines = height as u8;
|
||||
boottime_screen_info.video_type = BootTimeVideoType::Mda;
|
||||
boottime_screen_info.lfb_depth = 8;
|
||||
} else {
|
||||
//否则为图像模式,depth应参照帧缓冲区信息里面的每个像素的位数
|
||||
boottime_screen_info.lfb_width = width;
|
||||
boottime_screen_info.lfb_height = height;
|
||||
boottime_screen_info.video_type = BootTimeVideoType::Vlfb;
|
||||
boottime_screen_info.lfb_depth = fb_info.framebuffer_bpp as u8;
|
||||
}
|
||||
|
||||
boottime_screen_info.lfb_size =
|
||||
(width * height * ((fb_info.framebuffer_bpp as u32 + 7) / 8)) as usize;
|
||||
|
||||
let buf_vaddr = VirtAddr::new(0xffff800003200000);
|
||||
boottime_screen_info.lfb_virt_base = Some(buf_vaddr);
|
||||
|
||||
let init_text = "Video driver to map.\n\0";
|
||||
send_to_default_serial8250_port(init_text.as_bytes());
|
||||
|
||||
// 地址映射
|
||||
let paddr = PhysAddr::new(fb_info.framebuffer_addr as usize);
|
||||
let count =
|
||||
PageFrameCount::new(page_align_up(boottime_screen_info.lfb_size) / MMArch::PAGE_SIZE);
|
||||
unsafe { pseudo_map_phys(buf_vaddr, paddr, count) };
|
||||
return Ok(buf_vaddr);
|
||||
}
|
||||
|
||||
#[unified_init(INITCALL_DEVICE)]
|
||||
fn vesa_fb_device_init() -> Result<(), SystemError> {
|
||||
// 如果没有vesa帧缓冲区,直接返回
|
||||
if !HAS_VESA_FB.load(core::sync::atomic::Ordering::SeqCst) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
static INIT: Once = Once::new();
|
||||
INIT.call_once(|| {
|
||||
kinfo!("vesa fb device init");
|
||||
|
||||
let mut fix_info_guard = VESAFB_FIX_INFO.write_irqsave();
|
||||
let mut var_info_guard = 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;
|
||||
|
||||
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;
|
||||
} 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;
|
||||
}
|
||||
|
||||
drop(var_info_guard);
|
||||
drop(fix_info_guard);
|
||||
|
||||
let device = Arc::new(VesaFb::new());
|
||||
device_manager().device_default_initialize(&(device.clone() as Arc<dyn Device>));
|
||||
|
||||
platform_device_manager()
|
||||
.device_add(device.clone() as Arc<dyn PlatformDevice>)
|
||||
.expect("vesa_fb_device_init: platform_device_manager().device_add failed");
|
||||
|
||||
frame_buffer_manager()
|
||||
.register_fb(device.clone() as Arc<dyn FrameBuffer>)
|
||||
.expect("vesa_fb_device_init: frame_buffer_manager().register_fb failed");
|
||||
|
||||
// 设置vesa fb的状态为运行中
|
||||
device.inner.lock().fb_state = FbState::Running;
|
||||
});
|
||||
|
||||
return Ok(());
|
||||
}
|
@ -1,16 +1,12 @@
|
||||
use core::{
|
||||
ffi::{c_uint, c_void},
|
||||
mem::MaybeUninit,
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use crate::{
|
||||
arch::MMArch,
|
||||
driver::tty::serial::serial8250::send_to_default_serial8250_port,
|
||||
include::bindings::bindings::{
|
||||
multiboot2_get_Framebuffer_info, multiboot2_iter, multiboot_tag_framebuffer_info_t,
|
||||
FRAME_BUFFER_MAPPING_OFFSET, SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE,
|
||||
},
|
||||
init::boot_params,
|
||||
kinfo,
|
||||
libs::{
|
||||
align::page_align_up,
|
||||
@ -19,8 +15,8 @@ use crate::{
|
||||
spinlock::SpinLock,
|
||||
},
|
||||
mm::{
|
||||
allocator::page_frame::PageFrameCount, kernel_mapper::KernelMapper,
|
||||
no_init::pseudo_map_phys, page::PageFlags, MemoryManagementArch, PhysAddr, VirtAddr,
|
||||
allocator::page_frame::PageFrameCount, kernel_mapper::KernelMapper, page::PageFlags,
|
||||
MemoryManagementArch, VirtAddr,
|
||||
},
|
||||
time::timer::{Timer, TimerFunction},
|
||||
};
|
||||
@ -42,7 +38,6 @@ pub fn video_refresh_manager() -> &'static VideoRefreshManager {
|
||||
///管理显示刷新变量的结构体
|
||||
pub struct VideoRefreshManager {
|
||||
device_buffer: RwLock<ScmBufferInfo>,
|
||||
fb_info: multiboot_tag_framebuffer_info_t,
|
||||
refresh_target: RwLock<Option<Arc<SpinLock<Box<[u32]>>>>>,
|
||||
running: AtomicBool,
|
||||
}
|
||||
@ -94,6 +89,7 @@ impl VideoRefreshManager {
|
||||
let buf_vaddr = VirtAddr::new(
|
||||
SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE as usize + FRAME_BUFFER_MAPPING_OFFSET as usize,
|
||||
);
|
||||
boot_params().write_irqsave().screen_info.lfb_virt_base = Some(buf_vaddr);
|
||||
|
||||
let mut frame_buffer_info_graud = self.device_buffer.write();
|
||||
if let ScmBuffer::DeviceBuffer(vaddr) = &mut (frame_buffer_info_graud).buf {
|
||||
@ -101,7 +97,7 @@ impl VideoRefreshManager {
|
||||
}
|
||||
|
||||
// 地址映射
|
||||
let mut paddr = PhysAddr::new(self.fb_info.framebuffer_addr as usize);
|
||||
let mut paddr = boot_params().read().screen_info.lfb_base;
|
||||
let count = PageFrameCount::new(
|
||||
page_align_up(frame_buffer_info_graud.buf_size()) / MMArch::PAGE_SIZE,
|
||||
);
|
||||
@ -178,68 +174,48 @@ impl VideoRefreshManager {
|
||||
}
|
||||
|
||||
/// 此函数用于初始化显示驱动,为后续的图形输出做好准备。
|
||||
#[cfg(not(target_arch = "riscv64"))]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub unsafe fn video_init() -> Result<(), SystemError> {
|
||||
static INIT: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
if INIT
|
||||
.compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst)
|
||||
.is_err()
|
||||
{
|
||||
panic!("Try to init video twice!");
|
||||
}
|
||||
|
||||
let mut _reserved: u32 = 0;
|
||||
|
||||
let mut fb_info: MaybeUninit<multiboot_tag_framebuffer_info_t> = MaybeUninit::uninit();
|
||||
//从multiboot2中读取帧缓冲区信息至fb_info
|
||||
multiboot2_iter(
|
||||
Some(multiboot2_get_Framebuffer_info),
|
||||
fb_info.as_mut_ptr() as usize as *mut c_void,
|
||||
&mut _reserved as *mut c_uint,
|
||||
);
|
||||
fb_info.assume_init();
|
||||
let fb_info: multiboot_tag_framebuffer_info_t = core::mem::transmute(fb_info);
|
||||
|
||||
let width = fb_info.framebuffer_width;
|
||||
let height = fb_info.framebuffer_height;
|
||||
|
||||
//初始化帧缓冲区信息结构体
|
||||
let (bit_depth, flags) = if fb_info.framebuffer_type == 2 {
|
||||
//当type=2时,width与height用字符数表示,故depth=8
|
||||
|
||||
(8u32, ScmBufferFlag::SCM_BF_TEXT | ScmBufferFlag::SCM_BF_FB)
|
||||
} else {
|
||||
//否则为图像模式,depth应参照帧缓冲区信息里面的每个像素的位数
|
||||
(
|
||||
fb_info.framebuffer_bpp as u32,
|
||||
ScmBufferFlag::SCM_BF_PIXEL | ScmBufferFlag::SCM_BF_FB,
|
||||
)
|
||||
use crate::{
|
||||
arch::driver::video::arch_video_early_init,
|
||||
driver::video::fbdev::base::BootTimeVideoType,
|
||||
};
|
||||
|
||||
let buf_vaddr = VirtAddr::new(0xffff800003200000);
|
||||
let device_buffer = ScmBufferInfo::new_device_buffer(
|
||||
width,
|
||||
height,
|
||||
width * height * ((bit_depth + 7) / 8),
|
||||
bit_depth,
|
||||
flags,
|
||||
buf_vaddr,
|
||||
)
|
||||
.unwrap();
|
||||
arch_video_early_init()?;
|
||||
|
||||
let init_text = "Video driver to map.\n\0";
|
||||
send_to_default_serial8250_port(init_text.as_bytes());
|
||||
let boot_params_guard = boot_params().read();
|
||||
let screen_info = &boot_params_guard.screen_info;
|
||||
let buf_vaddr = screen_info.lfb_virt_base.unwrap();
|
||||
|
||||
//地址映射
|
||||
let paddr = PhysAddr::new(fb_info.framebuffer_addr as usize);
|
||||
let count = PageFrameCount::new(
|
||||
page_align_up(device_buffer.buf_size() as usize) / MMArch::PAGE_SIZE,
|
||||
);
|
||||
pseudo_map_phys(buf_vaddr, paddr, count);
|
||||
let buf_flag: ScmBufferFlag;
|
||||
let device_buffer: ScmBufferInfo;
|
||||
|
||||
if screen_info.video_type == BootTimeVideoType::Mda {
|
||||
buf_flag = ScmBufferFlag::SCM_BF_TEXT | ScmBufferFlag::SCM_BF_FB;
|
||||
device_buffer = ScmBufferInfo::new_device_buffer(
|
||||
screen_info.origin_video_cols.into(),
|
||||
screen_info.origin_video_lines.into(),
|
||||
screen_info.lfb_size as u32,
|
||||
screen_info.lfb_depth.into(),
|
||||
buf_flag,
|
||||
buf_vaddr,
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
// 图形模式
|
||||
buf_flag = ScmBufferFlag::SCM_BF_PIXEL | ScmBufferFlag::SCM_BF_FB;
|
||||
device_buffer = ScmBufferInfo::new_device_buffer(
|
||||
screen_info.lfb_width,
|
||||
screen_info.lfb_height,
|
||||
screen_info.lfb_size as u32,
|
||||
screen_info.lfb_depth.into(),
|
||||
buf_flag,
|
||||
buf_vaddr,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let result = Self {
|
||||
fb_info,
|
||||
device_buffer: RwLock::new(device_buffer),
|
||||
refresh_target: RwLock::new(None),
|
||||
running: AtomicBool::new(false),
|
||||
|
Reference in New Issue
Block a user