mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-25 18:23:22 +00:00
增加/dev/fb0,能够在用户程序读写帧缓冲区 (#485)
This commit is contained in:
@ -3,6 +3,7 @@ use core::intrinsics::unlikely;
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
use system_error::SystemError;
|
||||
@ -22,11 +23,19 @@ use crate::{
|
||||
kset::KSet,
|
||||
subsys::SubSysPrivate,
|
||||
},
|
||||
filesystem::{kernfs::KernFSInode, sysfs::AttributeGroup},
|
||||
filesystem::{
|
||||
devfs::{devfs_register, DevFS, DeviceINode},
|
||||
kernfs::KernFSInode,
|
||||
sysfs::AttributeGroup,
|
||||
vfs::{
|
||||
file::FileMode, syscall::ModeType, FilePrivateData, FileSystem, FileType, IndexNode,
|
||||
Metadata,
|
||||
},
|
||||
},
|
||||
init::initcall::INITCALL_SUBSYS,
|
||||
libs::{
|
||||
rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
spinlock::SpinLock,
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
},
|
||||
};
|
||||
|
||||
@ -141,6 +150,16 @@ impl FrameBufferManager {
|
||||
fb.set_fb_device(Some(fb_device.clone()));
|
||||
|
||||
device_manager().add_device(fb_device.clone() as Arc<dyn Device>)?;
|
||||
// 添加到devfs
|
||||
devfs_register(&fb_device.name(), fb_device.clone()).map_err(|e| {
|
||||
kerror!(
|
||||
"register fb device '{}' to devfs failed: {:?}",
|
||||
fb_device.name(),
|
||||
e
|
||||
);
|
||||
device_manager().remove(&(fb_device.clone() as Arc<dyn Device>));
|
||||
e
|
||||
})?;
|
||||
|
||||
// todo: 从Modedb中获取信息
|
||||
// 参考: https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/video/fbdev/core/fbmem.c#1584
|
||||
@ -195,7 +214,7 @@ pub struct FbDevice {
|
||||
impl FbDevice {
|
||||
pub const BASENAME: &'static str = "fb";
|
||||
fn new(fb: Weak<dyn FrameBuffer>, id: FbId) -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
let r = Arc::new(Self {
|
||||
inner: SpinLock::new(InnerFbDevice {
|
||||
fb,
|
||||
kern_inode: None,
|
||||
@ -203,14 +222,36 @@ impl FbDevice {
|
||||
kset: None,
|
||||
ktype: None,
|
||||
fb_id: id,
|
||||
device_inode_fs: None,
|
||||
devfs_metadata: Metadata::new(
|
||||
FileType::FramebufferDevice,
|
||||
ModeType::from_bits_truncate(0o666),
|
||||
),
|
||||
}),
|
||||
kobj_state: LockedKObjectState::new(None),
|
||||
})
|
||||
});
|
||||
|
||||
let mut inner_guard = r.inner.lock();
|
||||
|
||||
inner_guard.devfs_metadata.raw_dev = r.do_device_number(&inner_guard);
|
||||
drop(inner_guard);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
pub fn framebuffer(&self) -> Option<Arc<dyn FrameBuffer>> {
|
||||
self.inner.lock().fb.upgrade()
|
||||
}
|
||||
|
||||
/// 获取设备号
|
||||
pub fn device_number(&self) -> DeviceNumber {
|
||||
let inner_guard = self.inner.lock();
|
||||
self.do_device_number(&inner_guard)
|
||||
}
|
||||
|
||||
fn do_device_number(&self, inner_guard: &SpinLockGuard<'_, InnerFbDevice>) -> DeviceNumber {
|
||||
DeviceNumber::new(Major::FB_MAJOR, inner_guard.fb_id.data())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -222,6 +263,10 @@ struct InnerFbDevice {
|
||||
ktype: Option<&'static dyn KObjType>,
|
||||
/// 帧缓冲区id
|
||||
fb_id: FbId,
|
||||
|
||||
/// device inode要求的字段
|
||||
device_inode_fs: Option<Weak<DevFS>>,
|
||||
devfs_metadata: Metadata,
|
||||
}
|
||||
|
||||
impl KObject for FbDevice {
|
||||
@ -288,13 +333,7 @@ impl Device for FbDevice {
|
||||
}
|
||||
|
||||
fn id_table(&self) -> IdTable {
|
||||
IdTable::new(
|
||||
Self::BASENAME.to_string(),
|
||||
Some(DeviceNumber::new(
|
||||
Major::FB_MAJOR,
|
||||
self.inner.lock().fb_id.data(),
|
||||
)),
|
||||
)
|
||||
IdTable::new(Self::BASENAME.to_string(), Some(self.device_number()))
|
||||
}
|
||||
|
||||
fn set_bus(&self, _bus: Option<Weak<dyn Bus>>) {
|
||||
@ -336,3 +375,66 @@ impl Device for FbDevice {
|
||||
Some(&[&FbDeviceAttrGroup])
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceINode for FbDevice {
|
||||
fn set_fs(&self, fs: Weak<DevFS>) {
|
||||
self.inner.lock().device_inode_fs = Some(fs);
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexNode for FbDevice {
|
||||
fn open(&self, _data: &mut FilePrivateData, _mode: &FileMode) -> Result<(), SystemError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn close(&self, _data: &mut FilePrivateData) -> Result<(), SystemError> {
|
||||
Ok(())
|
||||
}
|
||||
fn read_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
len: usize,
|
||||
buf: &mut [u8],
|
||||
_data: &mut FilePrivateData,
|
||||
) -> Result<usize, SystemError> {
|
||||
let fb = self.inner.lock().fb.upgrade().unwrap();
|
||||
return fb.fb_read(&mut buf[0..len], offset);
|
||||
}
|
||||
|
||||
fn write_at(
|
||||
&self,
|
||||
offset: usize,
|
||||
len: usize,
|
||||
buf: &[u8],
|
||||
_data: &mut FilePrivateData,
|
||||
) -> Result<usize, SystemError> {
|
||||
let fb = self.inner.lock().fb.upgrade().unwrap();
|
||||
return fb.fb_write(&buf[0..len], offset);
|
||||
}
|
||||
|
||||
fn fs(&self) -> Arc<dyn FileSystem> {
|
||||
self.inner
|
||||
.lock()
|
||||
.device_inode_fs
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.upgrade()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn as_any_ref(&self) -> &dyn core::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn list(&self) -> Result<Vec<String>, SystemError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn metadata(&self) -> Result<Metadata, SystemError> {
|
||||
Ok(self.inner.lock().devfs_metadata.clone())
|
||||
}
|
||||
|
||||
fn resize(&self, _len: usize) -> Result<(), SystemError> {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
@ -295,6 +295,48 @@ impl FrameBufferOps for VesaFb {
|
||||
fn fb_destroy(&self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn fb_read(&self, buf: &mut [u8], pos: usize) -> Result<usize, SystemError> {
|
||||
let bp = boot_params().read();
|
||||
|
||||
let vaddr = bp.screen_info.lfb_virt_base.ok_or(SystemError::ENODEV)?;
|
||||
let size = self.current_fb_fix().smem_len;
|
||||
drop(bp);
|
||||
if pos >= size {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let pos = pos as i64;
|
||||
let size = size as i64;
|
||||
|
||||
let len = core::cmp::min(size - pos, buf.len() as i64) as usize;
|
||||
|
||||
let slice = unsafe { core::slice::from_raw_parts(vaddr.as_ptr::<u8>(), size as usize) };
|
||||
buf[..len].copy_from_slice(&slice[pos as usize..(pos as usize + len)]);
|
||||
|
||||
return Ok(len);
|
||||
}
|
||||
|
||||
fn fb_write(&self, buf: &[u8], pos: usize) -> Result<usize, SystemError> {
|
||||
let bp = boot_params().read();
|
||||
|
||||
let vaddr = bp.screen_info.lfb_virt_base.ok_or(SystemError::ENODEV)?;
|
||||
let size = self.current_fb_fix().smem_len;
|
||||
|
||||
if pos >= size {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let pos = pos as i64;
|
||||
let size = size as i64;
|
||||
|
||||
let len = core::cmp::min(size - pos, buf.len() as i64) as usize;
|
||||
|
||||
let slice = unsafe { core::slice::from_raw_parts_mut(vaddr.as_ptr::<u8>(), size as usize) };
|
||||
slice[pos as usize..(pos as usize + len)].copy_from_slice(&buf[..len]);
|
||||
|
||||
return Ok(len);
|
||||
}
|
||||
}
|
||||
|
||||
impl FrameBufferInfo for VesaFb {
|
||||
|
@ -91,15 +91,15 @@ impl VideoRefreshManager {
|
||||
);
|
||||
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 {
|
||||
let mut frame_buffer_info_guard = self.device_buffer.write();
|
||||
if let ScmBuffer::DeviceBuffer(vaddr) = &mut (frame_buffer_info_guard).buf {
|
||||
*vaddr = buf_vaddr;
|
||||
}
|
||||
|
||||
// 地址映射
|
||||
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,
|
||||
page_align_up(frame_buffer_info_guard.buf_size()) / MMArch::PAGE_SIZE,
|
||||
);
|
||||
let page_flags: PageFlags<MMArch> = PageFlags::new().set_execute(true).set_write(true);
|
||||
|
||||
|
Reference in New Issue
Block a user