From 08a2ee408498b0db4c76c57b149f1cf047758f3c Mon Sep 17 00:00:00 2001 From: LoGin Date: Wed, 20 Dec 2023 17:24:05 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0FrameBuffer=E7=9A=84=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E6=8A=BD=E8=B1=A1&=E5=AE=8C=E5=96=84=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E9=A9=B1=E5=8A=A8=E6=A8=A1=E5=9E=8B=E7=9A=84class?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81=20(#472)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 添加FrameBuffer的接口抽象(参考Linux 6.1.9) * feature: 完善设备驱动模型的class的抽象,并创建graphics class * feature: 完善设备驱动模型中Device对class的处理,使得能够在class下注册设备 目前注册了fbcon设备,但是由于虚拟终端还没写,因此fbcon的到终端以及帧缓冲区的映射还没加上去. --- kernel/src/driver/acpi/bus.rs | 7 +- kernel/src/driver/base/class.rs | 170 +++++- kernel/src/driver/base/cpu.rs | 12 +- kernel/src/driver/base/device/bus.rs | 2 +- kernel/src/driver/base/device/init.rs | 27 +- kernel/src/driver/base/device/mod.rs | 245 +++++++- kernel/src/driver/base/kobject.rs | 21 + kernel/src/driver/base/kset.rs | 16 + kernel/src/driver/base/platform/mod.rs | 2 +- .../driver/base/platform/platform_device.rs | 7 +- kernel/src/driver/base/platform/subsys.rs | 4 +- kernel/src/driver/base/subsys.rs | 23 +- kernel/src/driver/disk/ahci/ahcidisk.rs | 5 + kernel/src/driver/tty/mod.rs | 1 + .../src/driver/tty/serial/serial8250/mod.rs | 7 +- kernel/src/driver/tty/vt/mod.rs | 10 + kernel/src/driver/video/fbdev/base/fbcon.rs | 330 +++++++++++ kernel/src/driver/video/fbdev/base/fbmem.rs | 77 +++ kernel/src/driver/video/fbdev/base/mod.rs | 523 ++++++++++++++++++ kernel/src/driver/video/fbdev/mod.rs | 1 + kernel/src/driver/video/mod.rs | 2 + 21 files changed, 1442 insertions(+), 50 deletions(-) create mode 100644 kernel/src/driver/tty/vt/mod.rs create mode 100644 kernel/src/driver/video/fbdev/base/fbcon.rs create mode 100644 kernel/src/driver/video/fbdev/base/fbmem.rs create mode 100644 kernel/src/driver/video/fbdev/base/mod.rs create mode 100644 kernel/src/driver/video/fbdev/mod.rs diff --git a/kernel/src/driver/acpi/bus.rs b/kernel/src/driver/acpi/bus.rs index 4da1e11d..80dc1a64 100644 --- a/kernel/src/driver/acpi/bus.rs +++ b/kernel/src/driver/acpi/bus.rs @@ -1,6 +1,6 @@ use alloc::{ string::{String, ToString}, - sync::{Arc, Weak}, + sync::Arc, }; use crate::{ @@ -53,12 +53,11 @@ pub(super) struct AcpiBus { impl AcpiBus { pub fn new() -> Arc { - let default_weak: Weak = Weak::new(); let bus = Arc::new(Self { - private: SubSysPrivate::new("acpi".to_string(), default_weak, &[]), + private: SubSysPrivate::new("acpi".to_string(), None, None, &[]), }); bus.subsystem() - .set_bus(Arc::downgrade(&(bus.clone() as Arc))); + .set_bus(Some(Arc::downgrade(&(bus.clone() as Arc)))); return bus; } } diff --git a/kernel/src/driver/base/class.rs b/kernel/src/driver/base/class.rs index fb45be36..5fae0eec 100644 --- a/kernel/src/driver/base/class.rs +++ b/kernel/src/driver/base/class.rs @@ -1,8 +1,19 @@ use alloc::{string::ToString, sync::Arc}; -use crate::syscall::SystemError; +use core::fmt::Debug; -use super::kset::KSet; +use crate::{ + driver::video::fbdev::base::fbmem::fbmem_init, + filesystem::sysfs::{sysfs_instance, Attribute, AttributeGroup, SysFSOps}, + syscall::SystemError, +}; + +use super::{ + device::{sys_dev_char_kset, Device, DeviceMatchName, DeviceMatcher}, + kobject::{KObjType, KObject}, + kset::KSet, + subsys::SubSysPrivate, +}; /// `/sys/class`的kset static mut CLASS_KSET_INSTANCE: Option> = None; @@ -22,5 +33,160 @@ pub(super) fn classes_init() -> Result<(), SystemError> { unsafe { CLASS_KSET_INSTANCE = Some(class_kset); } + + fbmem_init()?; return Ok(()); } + +/// 设备分类 +/// +/// 类是对设备的高级视图,它抽象了低级实现细节。 +/// +/// 比如,驱动程序可能看到一个SCSI硬盘或一个ATA硬盘,但在类的这个级别,它们都只是硬盘。 +/// 类允许用户空间根据设备的功能而不是它们如何连接或工作来操作设备。 +/// +/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/device/class.h#54 +pub trait Class: Debug + Send + Sync { + /// 获取类的名称 + fn name(&self) -> &'static str; + + /// 属于该类的设备的基本属性。 + fn dev_groups(&self) -> &'static [&'static dyn AttributeGroup] { + return &[]; + } + + /// 当前类的基本属性。 + fn class_groups(&self) -> &'static [&'static dyn AttributeGroup] { + return &[]; + } + + /// 表示此类的kobject,并将它链接到层次结构中。 + /// + /// 当前class的所有设备,将会挂载到的`/sys/dev/`内的某个目录下。 + fn dev_kobj(&self) -> Option>; + + fn set_dev_kobj(&self, kobj: Arc); + + /// subsystem应当拥有的数据 + fn subsystem(&self) -> &SubSysPrivate; + + /// Called to release this class + fn class_release(&self) {} +} + +impl dyn Class { + /// 在class内,根据条件寻找一个特定的设备 + /// + /// ## 参数 + /// + /// - `matcher` - 匹配器 + /// - `data` - 传给匹配器的数据 + #[allow(dead_code)] + pub fn find_device( + &self, + matcher: &dyn DeviceMatcher, + data: T, + ) -> Option> { + let subsys = self.subsystem(); + let guard = subsys.devices(); + for dev in guard.iter() { + let dev = dev.upgrade(); + if let Some(dev) = dev { + if matcher.match_device(&dev, data) { + return Some(dev.clone()); + } + } + } + return None; + } + + /// 根据名称匹配设备 + /// + /// ## 参数 + /// + /// - name 设备名称 + #[allow(dead_code)] + pub fn find_device_by_name(&self, name: &str) -> Option> { + return self.find_device(&DeviceMatchName, name); + } +} + +#[inline(always)] +pub fn class_manager() -> &'static ClassManager { + return &ClassManager; +} +pub struct ClassManager; + +impl ClassManager { + /// 注册一个设备类 + /// + /// 该方法会将设备类注册到`/sys/class`目录下, + /// 并创建它的默认属性组对应的文件。 + /// + /// ## 参数 + /// + /// - `class` - 设备类 + pub fn class_register(&self, class: &Arc) -> Result<(), SystemError> { + let subsystem = class.subsystem(); + let subsys = subsystem.subsys(); + subsys.set_name(class.name().to_string()); + + if class.dev_kobj().is_none() { + class.set_dev_kobj(sys_dev_char_kset() as Arc); + } + + subsys.set_kobj_type(Some(&ClassKObjbectType)); + subsystem.set_class(Some(Arc::downgrade(class))); + + subsys.register(Some(sys_class_kset()))?; + + sysfs_instance().create_groups(&(subsys as Arc), class.class_groups())?; + + return Ok(()); + } + + /// 注销一个设备类 + #[allow(dead_code)] + pub fn class_unregister(&self, class: &Arc) { + let subsystem = class.subsystem(); + let subsys = subsystem.subsys(); + sysfs_instance().remove_groups(&(subsys.clone() as Arc), class.class_groups()); + subsys.unregister(); + } +} + +#[derive(Debug)] +pub struct ClassKObjbectType; + +impl KObjType for ClassKObjbectType { + fn sysfs_ops(&self) -> Option<&dyn SysFSOps> { + Some(&ClassSysFSOps) + } + + fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> { + None + } +} + +#[derive(Debug)] +struct ClassSysFSOps; + +impl SysFSOps for ClassSysFSOps { + fn show( + &self, + _kobj: Arc, + _attr: &dyn Attribute, + _buf: &mut [u8], + ) -> Result { + todo!() + } + + fn store( + &self, + _kobj: Arc, + _attr: &dyn Attribute, + _buf: &[u8], + ) -> Result { + todo!() + } +} diff --git a/kernel/src/driver/base/cpu.rs b/kernel/src/driver/base/cpu.rs index 6d2611cd..09675290 100644 --- a/kernel/src/driver/base/cpu.rs +++ b/kernel/src/driver/base/cpu.rs @@ -13,6 +13,7 @@ use crate::{ }; use super::{ + class::Class, device::{ bus::{subsystem_manager, Bus}, driver::Driver, @@ -59,12 +60,11 @@ struct CpuSubSystem { impl CpuSubSystem { pub fn new() -> Arc { - let default_weak: Weak = Weak::new(); let bus = Arc::new(Self { - subsys_private: SubSysPrivate::new("cpu".to_string(), default_weak, &[]), + subsys_private: SubSysPrivate::new("cpu".to_string(), None, None, &[]), }); bus.subsystem() - .set_bus(Arc::downgrade(&(bus.clone() as Arc))); + .set_bus(Some(Arc::downgrade(&(bus.clone() as Arc)))); return bus; } } @@ -149,7 +149,7 @@ impl Device for CpuSubSystemFakeRootDevice { } fn id_table(&self) -> IdTable { - IdTable::new("cpu".to_string(), DeviceNumber::new(0)) + IdTable::new("cpu".to_string(), Some(DeviceNumber::new(0))) } fn set_bus(&self, bus: Option>) { @@ -179,6 +179,10 @@ impl Device for CpuSubSystemFakeRootDevice { fn state_synced(&self) -> bool { true } + + fn set_class(&self, _class: Option>) { + todo!() + } } impl KObject for CpuSubSystemFakeRootDevice { diff --git a/kernel/src/driver/base/device/bus.rs b/kernel/src/driver/base/device/bus.rs index bc5f71f5..a0e6a906 100644 --- a/kernel/src/driver/base/device/bus.rs +++ b/kernel/src/driver/base/device/bus.rs @@ -353,7 +353,7 @@ impl BusManager { /// /// todo: 增加错误处理逻辑 pub fn register(&self, bus: Arc) -> Result<(), SystemError> { - bus.subsystem().set_bus(Arc::downgrade(&bus)); + bus.subsystem().set_bus(Some(Arc::downgrade(&bus))); let subsys_kset = bus.subsystem().subsys(); subsys_kset.set_name(bus.name()); diff --git a/kernel/src/driver/base/device/init.rs b/kernel/src/driver/base/device/init.rs index 2b07014c..5a7919f8 100644 --- a/kernel/src/driver/base/device/init.rs +++ b/kernel/src/driver/base/device/init.rs @@ -3,12 +3,14 @@ use alloc::{string::ToString, sync::Arc}; use crate::{ driver::base::{ device::{ - sys_dev_kset, DeviceManager, DEVICES_KSET_INSTANCE, DEVICE_MANAGER, DEV_KSET_INSTANCE, + set_sys_dev_block_kset, set_sys_dev_char_kset, set_sys_devices_virtual_kset, + sys_dev_kset, sys_devices_kset, DeviceManager, DEVICES_KSET_INSTANCE, DEVICE_MANAGER, + DEV_KSET_INSTANCE, }, kobject::KObject, kset::KSet, }, - kdebug, kinfo, + kinfo, syscall::SystemError, }; @@ -27,6 +29,19 @@ pub fn devices_init() -> Result<(), SystemError> { } } + // 创建 `/sys/devices/virtual` 目录 + { + let devices_kset = sys_devices_kset(); + let virtual_kset = KSet::new("virtual".to_string()); + let parent = devices_kset.clone() as Arc; + virtual_kset.set_parent(Some(Arc::downgrade(&parent))); + + virtual_kset + .register(Some(devices_kset)) + .expect("register virtual kset failed"); + unsafe { set_sys_devices_virtual_kset(virtual_kset) }; + } + // 创建 `/sys/dev` 目录 { let dev_kset = KSet::new("dev".to_string()); @@ -38,7 +53,7 @@ pub fn devices_init() -> Result<(), SystemError> { // 创建 `/sys/dev/block` 目录 { - kdebug!("create /sys/dev/block"); + // kdebug!("create /sys/dev/block"); let dev_kset = sys_dev_kset(); let dev_block_kset = KSet::new("block".to_string()); let parent = dev_kset.clone() as Arc; @@ -47,11 +62,13 @@ pub fn devices_init() -> Result<(), SystemError> { dev_block_kset .register(Some(dev_kset)) .expect("register dev block kset failed"); + + unsafe { set_sys_dev_block_kset(dev_block_kset) }; } // 创建 `/sys/dev/char` 目录 { - kdebug!("create /sys/dev/char"); + // kdebug!("create /sys/dev/char"); let dev_kset = sys_dev_kset(); let dev_char_kset = KSet::new("char".to_string()); let parent = dev_kset.clone() as Arc; @@ -60,6 +77,8 @@ pub fn devices_init() -> Result<(), SystemError> { dev_char_kset .register(Some(dev_kset)) .expect("register dev char kset failed"); + + unsafe { set_sys_dev_char_kset(dev_char_kset) }; } kinfo!("devices init success"); diff --git a/kernel/src/driver/base/device/mod.rs b/kernel/src/driver/base/device/mod.rs index 0d3ecb64..7d86f4ca 100644 --- a/kernel/src/driver/base/device/mod.rs +++ b/kernel/src/driver/base/device/mod.rs @@ -27,6 +27,7 @@ use self::{ }; use super::{ + class::Class, kobject::{KObjType, KObject, KObjectManager, KObjectState}, kset::KSet, swnode::software_node_notify, @@ -65,27 +66,51 @@ static mut DEV_BLOCK_KSET_INSTANCE: Option> = None; /// `/sys/dev/char` 的 kset 实例 static mut DEV_CHAR_KSET_INSTANCE: Option> = None; +/// `/sys/devices/virtual` 的 kset 实例 +static mut DEVICES_VIRTUAL_KSET_INSTANCE: Option> = None; + +/// 获取`/sys/devices`的kset实例 #[inline(always)] pub(super) fn sys_devices_kset() -> Arc { unsafe { DEVICES_KSET_INSTANCE.as_ref().unwrap().clone() } } +/// 获取`/sys/dev`的kset实例 #[inline(always)] pub(super) fn sys_dev_kset() -> Arc { unsafe { DEV_KSET_INSTANCE.as_ref().unwrap().clone() } } +/// 获取`/sys/dev/block`的kset实例 #[inline(always)] #[allow(dead_code)] -pub(super) fn sys_dev_block_kset() -> Arc { +pub fn sys_dev_block_kset() -> Arc { unsafe { DEV_BLOCK_KSET_INSTANCE.as_ref().unwrap().clone() } } +/// 获取`/sys/dev/char`的kset实例 #[inline(always)] -pub(self) fn sys_dev_char_kset() -> Arc { +pub fn sys_dev_char_kset() -> Arc { unsafe { DEV_CHAR_KSET_INSTANCE.as_ref().unwrap().clone() } } +pub(self) unsafe fn set_sys_dev_block_kset(kset: Arc) { + DEV_BLOCK_KSET_INSTANCE = Some(kset); +} + +pub(self) unsafe fn set_sys_dev_char_kset(kset: Arc) { + DEV_CHAR_KSET_INSTANCE = Some(kset); +} + +/// 获取`/sys/devices/virtual`的kset实例 +pub fn sys_devices_virtual_kset() -> Arc { + unsafe { DEVICES_VIRTUAL_KSET_INSTANCE.as_ref().unwrap().clone() } +} + +pub(self) unsafe fn set_sys_devices_virtual_kset(kset: Arc) { + DEVICES_VIRTUAL_KSET_INSTANCE = Some(kset); +} + /// 设备应该实现的操作 /// /// ## 注意 @@ -126,6 +151,14 @@ pub trait Device: KObject { /// (一定要传入Arc,因为bus的subsysprivate里面存储的是Device的Weak指针) fn set_bus(&self, bus: Option>); + /// 获取当前设备所属的类 + fn class(&self) -> Option> { + return None; + } + + /// 设置当前设备所属的类 + fn set_class(&self, class: Option>); + /// 返回已经与当前设备匹配好的驱动程序 fn driver(&self) -> Option>; @@ -147,6 +180,10 @@ pub trait Device: KObject { /// the software state of this device by calling the driver/bus /// sync_state() callback. fn state_synced(&self) -> bool; + + fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> { + None + } } impl dyn Device { @@ -252,11 +289,15 @@ pub enum DeviceType { Serial, Intc, PlatformDev, + Char, } /// @brief: 设备标识符类型 #[derive(Debug, Clone, Hash, PartialOrd, PartialEq, Ord, Eq)] -pub struct IdTable(String, DeviceNumber); +pub struct IdTable { + basename: String, + id: Option, +} /// @brief: 设备标识符操作方法集 impl IdTable { @@ -264,25 +305,29 @@ impl IdTable { /// @parameter name: 设备名 /// @parameter id: 设备id /// @return: 设备标识符 - pub fn new(name: String, id: DeviceNumber) -> IdTable { - Self(name, id) + pub fn new(basename: String, id: Option) -> IdTable { + return IdTable { basename, id }; } /// @brief: 将设备标识符转换成name /// @parameter None /// @return: 设备名 pub fn name(&self) -> String { - return format!("{}:{}", self.0, self.1 .0); + if self.id.is_none() { + return self.basename.clone(); + } else { + return format!("{}:{}", self.basename, self.id.unwrap().data()); + } } pub fn device_number(&self) -> DeviceNumber { - return self.1; + return self.id.unwrap_or(DeviceNumber::new(0)); } } impl Default for IdTable { fn default() -> Self { - IdTable("unknown".to_string(), DeviceNumber::new(0)) + IdTable::new("unknown".to_string(), None) } } @@ -435,7 +480,25 @@ impl DeviceManager { #[inline] #[allow(dead_code)] pub fn add_device(&self, device: Arc) -> Result<(), SystemError> { - // todo: 引入class后,在这里处理与parent相关的逻辑 + // 在这里处理与parent相关的逻辑 + + let current_parent = device + .parent() + .map(|x| x.upgrade()) + .flatten() + .map(|x| x.arc_any().cast::().ok()) + .flatten(); + + let actual_parent = self.get_device_parent(&device, current_parent)?; + if let Some(actual_parent) = actual_parent { + // kdebug!( + // "device '{}' parent is '{}', strong_count: {}", + // device.name().to_string(), + // actual_parent.name(), + // Arc::strong_count(&actual_parent) + // ); + device.set_parent(Some(Arc::downgrade(&actual_parent))); + } KObjectManager::add_kobj(device.clone() as Arc, None).map_err(|e| { kerror!("add device '{:?}' failed: {:?}", device.name(), e); @@ -456,18 +519,85 @@ impl DeviceManager { self.create_sys_dev_entry(&device)?; } - // todo: Notify clients of device addition.This call must come - // after dpm_sysfs_add() and before kobject_uevent(). - // 参考:https://opengrok.ringotek.cn/xref/linux-6.1.9/drivers/base/core.c#3491 + // 通知客户端有关设备添加的信息。此调用必须在 dpm_sysfs_add() 之后且在 kobject_uevent() 之前执行。 + if let Some(bus) = device.bus() { + bus.subsystem().bus_notifier().call_chain( + bus::BusNotifyEvent::AddDevice, + Some(&device), + None, + ); + } - // todo: 发送uevent + // todo: 发送uevent: KOBJ_ADD // probe drivers for a new device bus_probe_device(&device); + if let Some(class) = device.class() { + class.subsystem().add_device_to_vec(&device)?; + + for class_interface in class.subsystem().interfaces() { + class_interface.add_device(&device).ok(); + } + } + return Ok(()); } + /// 获取设备真实的parent kobject + /// + /// ## 参数 + /// + /// - `device`: 设备 + /// - `current_parent`: 当前的parent kobject + /// + /// ## 返回值 + /// + /// - `Ok(Some(kobj))`: 如果找到了真实的parent kobject,那么返回它 + /// - `Ok(None)`: 如果没有找到真实的parent kobject,那么返回None + /// - `Err(e)`: 如果发生错误,那么返回错误 + fn get_device_parent( + &self, + device: &Arc, + current_parent: Option>, + ) -> Result>, SystemError> { + // kdebug!("get_device_parent() device:{:?}", device.name()); + if let Some(_) = device.class() { + let parent_kobj: Arc; + // kdebug!("current_parent:{:?}", current_parent); + if current_parent.is_none() { + parent_kobj = sys_devices_virtual_kset() as Arc; + } else { + let cp = current_parent.unwrap(); + + if cp.class().is_some() { + return Ok(Some(cp.clone() as Arc)); + } else { + parent_kobj = cp.clone() as Arc; + } + } + + // 是否需要glue dir? + + return Ok(Some(parent_kobj)); + } + + // subsystems can specify a default root directory for their devices + if current_parent.is_none() { + if let Some(bus) = device.bus() { + if let Some(root) = bus.root_device().map(|x| x.upgrade()).flatten() { + return Ok(Some(root as Arc)); + } + } + } + + if current_parent.is_some() { + return Ok(Some(current_parent.unwrap().clone() as Arc)); + } + + return Ok(None); + } + /// @brief: 卸载设备 /// @parameter id_table: 总线标识符,用于唯一标识该设备 /// @return: None @@ -496,9 +626,32 @@ impl DeviceManager { software_node_notify(dev); } - fn add_class_symlinks(&self, _dev: &Arc) -> Result<(), SystemError> { - // todo: 引入class后,在这里处理与class相关的逻辑 - // https://opengrok.ringotek.cn/xref/linux-6.1.9/drivers/base/core.c#3224 + fn add_class_symlinks(&self, dev: &Arc) -> Result<(), SystemError> { + let class = dev.class(); + if class.is_none() { + return Ok(()); + } + + // 定义错误处理函数,用于在添加符号链接失败时,移除已经添加的符号链接 + + let err_remove_subsystem = |dev_kobj: &Arc| { + sysfs_instance().remove_link(dev_kobj, "subsystem".to_string()); + }; + + let class = class.unwrap(); + let dev_kobj = dev.clone() as Arc; + let subsys_kobj = class.subsystem().subsys() as Arc; + sysfs_instance().create_link(Some(&dev_kobj), &subsys_kobj, "subsystem".to_string())?; + + // todo: 这里需要处理class的parent逻辑, 添加device链接 + // https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/base/core.c#3245 + + sysfs_instance() + .create_link(Some(&subsys_kobj), &dev_kobj, dev.name()) + .map_err(|e| { + err_remove_subsystem(&dev_kobj); + e + })?; return Ok(()); } @@ -509,20 +662,45 @@ impl DeviceManager { /// /// - `dev`: 设备 fn add_attrs(&self, dev: &Arc) -> Result<(), SystemError> { - let kobj_type = dev.kobj_type(); - if kobj_type.is_none() { - return Ok(()); + // 定义错误处理函数,用于在添加属性文件失败时,移除已经添加的属性组 + let err_remove_class_groups = |dev: &Arc| { + if let Some(class) = dev.class() { + let attr_groups = class.dev_groups(); + self.remove_groups(dev, attr_groups); + } + }; + + let err_remove_kobj_type_groups = |dev: &Arc| { + if let Some(kobj_type) = dev.kobj_type() { + let attr_groups = kobj_type.attribute_groups().unwrap_or(&[]); + self.remove_groups(dev, attr_groups); + } + }; + + // 真正开始添加属性文件 + + // 添加设备类的属性文件 + if let Some(class) = dev.class() { + let attr_groups = class.dev_groups(); + self.add_groups(dev, attr_groups)?; } - let kobj_type = kobj_type.unwrap(); - - let attr_groups = kobj_type.attribute_groups(); - - if attr_groups.is_none() { - return Ok(()); + // 添加kobj_type的属性文件 + if let Some(kobj_type) = dev.kobj_type() { + self.add_groups(dev, kobj_type.attribute_groups().unwrap_or(&[])) + .map_err(|e| { + err_remove_class_groups(dev); + e + })?; } - self.add_groups(dev, attr_groups.unwrap())?; + // 添加设备本身的属性文件 + self.add_groups(dev, dev.attribute_groups().unwrap_or(&[])) + .map_err(|e| { + err_remove_kobj_type_groups(dev); + err_remove_class_groups(dev); + e + })?; return Ok(()); } @@ -542,6 +720,21 @@ impl DeviceManager { return sysfs_instance().create_groups(&kobj, attr_groups); } + /// 在sysfs中,为指定的设备移除属性组,以及属性组中的属性文件 + /// + /// ## 参数 + /// + /// - `dev`: 设备 + /// - `attr_groups`: 要移除的属性组 + pub fn remove_groups( + &self, + dev: &Arc, + attr_groups: &'static [&dyn AttributeGroup], + ) { + let kobj = dev.clone() as Arc; + sysfs_instance().remove_groups(&kobj, attr_groups); + } + /// 为设备在sysfs中创建属性文件 /// /// ## 参数 diff --git a/kernel/src/driver/base/kobject.rs b/kernel/src/driver/base/kobject.rs index 279ae934..109b10ea 100644 --- a/kernel/src/driver/base/kobject.rs +++ b/kernel/src/driver/base/kobject.rs @@ -73,6 +73,7 @@ impl DowncastArc for dyn KObject { } pub trait KObjType: Debug + Send + Sync { + /// 当指定的kobject被释放时,设备驱动模型会调用此方法 fn release(&self, _kobj: Arc) {} fn sysfs_ops(&self) -> Option<&dyn SysFSOps>; @@ -225,6 +226,26 @@ impl KObjectManager { return Ok(()); } + + /// 从sysfs中移除kobject + pub fn remove_kobj(kobj: Arc) { + let ktype = kobj.kobj_type(); + if let Some(ktype) = ktype { + if let Some(groups) = ktype.attribute_groups() { + sysfs_instance().remove_groups(&kobj, groups); + } + } + + // todo: 发送uevent: KOBJ_REMOVE + + sysfs_instance().remove_dir(&kobj); + kobj.update_kobj_state(None, Some(KObjectState::IN_SYSFS)); + let kset = kobj.kset(); + if let Some(kset) = kset { + kset.leave(&kobj); + } + kobj.set_parent(None); + } } /// 动态创建的kobject对象的ktype diff --git a/kernel/src/driver/base/kset.rs b/kernel/src/driver/base/kset.rs index daee885a..65f53cfb 100644 --- a/kernel/src/driver/base/kset.rs +++ b/kernel/src/driver/base/kset.rs @@ -84,11 +84,22 @@ impl KSet { return Ok(kset); } + /// 注册一个kset + /// + /// ## 参数 + /// + /// - join_kset: 如果不为None,那么这个kset会加入到join_kset中 pub fn register(&self, join_kset: Option>) -> Result<(), SystemError> { return KObjectManager::add_kobj(self.self_ref.upgrade().unwrap(), join_kset); // todo: 引入uevent之后,发送uevent } + /// 注销一个kset + #[allow(dead_code)] + pub fn unregister(&self) { + KObjectManager::remove_kobj(self.self_ref.upgrade().unwrap()); + } + /// 把一个kobject加入到当前kset中。 /// /// 该函数不会修改kobj的parent,需要调用者自己视情况修改。 @@ -105,6 +116,7 @@ impl KSet { /// 把一个kobject从当前kset中移除。 pub fn leave(&self, kobj: &Arc) { let mut kobjects = self.kobjects.write(); + kobjects.retain(|x| x.upgrade().is_some()); let index = kobjects.iter().position(|x| { if let Some(x) = x.upgrade() { return Arc::ptr_eq(&x, kobj); @@ -129,6 +141,10 @@ impl KSet { pub fn as_kobject(&self) -> Arc { return self.self_ref.upgrade().unwrap(); } + + pub fn kobjects(&self) -> RwLockReadGuard>> { + return self.kobjects.read(); + } } impl KObject for KSet { diff --git a/kernel/src/driver/base/platform/mod.rs b/kernel/src/driver/base/platform/mod.rs index 12e3141a..398992dd 100644 --- a/kernel/src/driver/base/platform/mod.rs +++ b/kernel/src/driver/base/platform/mod.rs @@ -73,7 +73,7 @@ impl CompatibleTable { pub fn platform_bus_init() -> Result<(), SystemError> { let platform_device: Arc = PlatformBusDevice::new( DevicePrivateData::new( - IdTable::new("platform".to_string(), DeviceNumber::new(0)), + IdTable::new("platform".to_string(), Some(DeviceNumber::new(0))), BusState::NotInitialized.into(), ), Some(Arc::downgrade(&(sys_devices_kset() as Arc))), diff --git a/kernel/src/driver/base/platform/platform_device.rs b/kernel/src/driver/base/platform/platform_device.rs index 4b4bb28f..6792df15 100644 --- a/kernel/src/driver/base/platform/platform_device.rs +++ b/kernel/src/driver/base/platform/platform_device.rs @@ -6,6 +6,7 @@ use ida::IdAllocator; use crate::{ driver::base::{ + class::Class, device::{ bus::{Bus, BusState}, device_manager, @@ -287,7 +288,7 @@ impl Device for PlatformBusDevice { #[inline] #[allow(dead_code)] fn id_table(&self) -> IdTable { - IdTable::new("platform".to_string(), DeviceNumber::new(0)) + IdTable::new("platform".to_string(), Some(DeviceNumber::new(0))) } fn bus(&self) -> Option> { @@ -322,4 +323,8 @@ impl Device for PlatformBusDevice { fn state_synced(&self) -> bool { todo!() } + + fn set_class(&self, _class: Option>) { + todo!() + } } diff --git a/kernel/src/driver/base/platform/subsys.rs b/kernel/src/driver/base/platform/subsys.rs index a057236b..c8ce5626 100644 --- a/kernel/src/driver/base/platform/subsys.rs +++ b/kernel/src/driver/base/platform/subsys.rs @@ -30,10 +30,10 @@ pub struct PlatformBus { impl PlatformBus { pub fn new() -> Arc { let w: Weak = Weak::new(); - let private = SubSysPrivate::new("platform".to_string(), w, &[]); + let private = SubSysPrivate::new("platform".to_string(), Some(w), None, &[]); let bus = Arc::new(Self { private }); bus.subsystem() - .set_bus(Arc::downgrade(&(bus.clone() as Arc))); + .set_bus(Some(Arc::downgrade(&(bus.clone() as Arc)))); return bus; } diff --git a/kernel/src/driver/base/subsys.rs b/kernel/src/driver/base/subsys.rs index 5849c53a..a6818fd5 100644 --- a/kernel/src/driver/base/subsys.rs +++ b/kernel/src/driver/base/subsys.rs @@ -19,6 +19,7 @@ use crate::{ }; use super::{ + class::Class, device::{ bus::{Bus, BusNotifyEvent}, driver::Driver, @@ -34,7 +35,9 @@ pub struct SubSysPrivate { subsys: Arc, ksets: RwLock, /// 指向拥有当前结构体的`dyn bus`对象的弱引用 - bus: SpinLock>, + bus: SpinLock>>, + /// 指向拥有当前结构体的`dyn class`对象的弱引用 + class: SpinLock>>, drivers_autoprobe: AtomicBool, /// 当前总线上的所有设备 devices: RwLock>>, @@ -64,7 +67,8 @@ impl SubSysKSets { impl SubSysPrivate { pub fn new( name: String, - bus: Weak, + bus: Option>, + class: Option>, interfaces: &'static [&'static dyn SubSysInterface], ) -> Self { let subsys = KSet::new(name); @@ -73,6 +77,7 @@ impl SubSysPrivate { ksets: RwLock::new(SubSysKSets::new()), drivers_autoprobe: AtomicBool::new(false), bus: SpinLock::new(bus), + class: SpinLock::new(class), devices: RwLock::new(Vec::new()), drivers: RwLock::new(Vec::new()), interfaces, @@ -86,14 +91,24 @@ impl SubSysPrivate { #[inline] #[allow(dead_code)] - pub fn bus(&self) -> Weak { + pub fn bus(&self) -> Option> { return self.bus.lock().clone(); } - pub fn set_bus(&self, bus: Weak) { + pub fn set_bus(&self, bus: Option>) { *self.bus.lock() = bus; } + #[allow(dead_code)] + #[inline] + pub fn class(&self) -> Option> { + return self.class.lock().clone(); + } + + pub fn set_class(&self, class: Option>) { + *self.class.lock() = class; + } + pub fn devices(&self) -> RwLockReadGuard>> { return self.devices.read(); } diff --git a/kernel/src/driver/disk/ahci/ahcidisk.rs b/kernel/src/driver/disk/ahci/ahcidisk.rs index 48f9aacc..07aa0263 100644 --- a/kernel/src/driver/disk/ahci/ahcidisk.rs +++ b/kernel/src/driver/disk/ahci/ahcidisk.rs @@ -2,6 +2,7 @@ use super::{_port, hba::HbaCmdTable, virt_2_phys}; use crate::driver::base::block::block_device::{BlockDevice, BlockId}; use crate::driver::base::block::disk_info::Partition; use crate::driver::base::block::SeekFrom; +use crate::driver::base::class::Class; use crate::driver::base::device::bus::Bus; use crate::driver::base::device::driver::Driver; @@ -529,6 +530,10 @@ impl Device for LockedAhciDisk { fn state_synced(&self) -> bool { todo!() } + + fn set_class(&self, _class: Option>) { + todo!() + } } impl BlockDevice for LockedAhciDisk { diff --git a/kernel/src/driver/tty/mod.rs b/kernel/src/driver/tty/mod.rs index c32bd6b4..692ea4ec 100644 --- a/kernel/src/driver/tty/mod.rs +++ b/kernel/src/driver/tty/mod.rs @@ -13,6 +13,7 @@ pub mod init; pub mod serial; pub mod tty_device; pub mod tty_driver; +pub mod vt; bitflags! { pub struct TtyCoreState: u32{ diff --git a/kernel/src/driver/tty/serial/serial8250/mod.rs b/kernel/src/driver/tty/serial/serial8250/mod.rs index fa13faeb..2792ec30 100644 --- a/kernel/src/driver/tty/serial/serial8250/mod.rs +++ b/kernel/src/driver/tty/serial/serial8250/mod.rs @@ -12,6 +12,7 @@ use alloc::{ use crate::{ driver::{ base::{ + class::Class, device::{ bus::Bus, device_manager, driver::Driver, Device, DeviceKObjType, DeviceNumber, DeviceState, DeviceType, IdTable, @@ -228,7 +229,7 @@ impl Device for Serial8250ISADevices { } fn id_table(&self) -> IdTable { - return IdTable::new(self.name.to_string(), DeviceNumber::new(0)); + return IdTable::new(self.name.to_string(), Some(DeviceNumber::new(0))); } fn driver(&self) -> Option> { @@ -250,6 +251,10 @@ impl Device for Serial8250ISADevices { fn state_synced(&self) -> bool { true } + + fn set_class(&self, _class: Option>) { + todo!() + } } impl KObject for Serial8250ISADevices { diff --git a/kernel/src/driver/tty/vt/mod.rs b/kernel/src/driver/tty/vt/mod.rs new file mode 100644 index 00000000..dcbb36b0 --- /dev/null +++ b/kernel/src/driver/tty/vt/mod.rs @@ -0,0 +1,10 @@ +//! Virtual terminal driver. +//! +//! (TODO) This driver is not implemented yet. + +/// The minimum number of virtual terminals. +#[allow(dead_code)] +pub const MIN_NR_CONSOLES: usize = 1; +/// The maximum number of virtual terminals. +#[allow(dead_code)] +pub const MAX_NR_CONSOLES: usize = 63; diff --git a/kernel/src/driver/video/fbdev/base/fbcon.rs b/kernel/src/driver/video/fbdev/base/fbcon.rs new file mode 100644 index 00000000..a0173441 --- /dev/null +++ b/kernel/src/driver/video/fbdev/base/fbcon.rs @@ -0,0 +1,330 @@ +use alloc::{ + string::{String, ToString}, + sync::{Arc, Weak}, +}; + +use crate::{ + driver::base::{ + class::Class, + device::{bus::Bus, device_manager, driver::Driver, Device, DeviceType, IdTable}, + kobject::{KObjType, KObject, KObjectState, LockedKObjectState}, + kset::KSet, + }, + filesystem::{ + kernfs::KernFSInode, + sysfs::{file::sysfs_emit_str, Attribute, AttributeGroup, SysFSOpsSupport}, + vfs::syscall::ModeType, + }, + libs::{ + rwlock::{RwLockReadGuard, RwLockWriteGuard}, + spinlock::SpinLock, + }, + syscall::SystemError, +}; + +use super::fbmem::sys_class_graphics_instance; + +/// framebuffer console设备管理器实例 +static mut FB_CONSOLE_MANAGER: Option = None; + +pub fn fb_console_manager() -> &'static FbConsoleManager { + unsafe { FB_CONSOLE_MANAGER.as_ref().unwrap() } +} + +/// 初始化framebuffer console +pub(super) fn fb_console_init() -> Result<(), SystemError> { + // todo: 对全局的console信号量加锁(linux中是console_lock) + + let fbcon_device: Arc = FbConsoleDevice::new(); + + { + let fbcon_manager = FbConsoleManager::new(fbcon_device.clone()); + unsafe { FB_CONSOLE_MANAGER = Some(fbcon_manager) }; + } + + device_manager().register(fbcon_device.clone() as Arc)?; + fb_console_manager().init_device()?; + + return Ok(()); +} + +/// framebuffer console设备管理器 +#[derive(Debug)] +pub struct FbConsoleManager { + _inner: SpinLock, + /// framebuffer console设备实例 + /// (对应`/sys/class/graphics/fbcon`) + device: Arc, +} + +impl FbConsoleManager { + pub fn new(device: Arc) -> Self { + return Self { + _inner: SpinLock::new(InnerFbConsoleManager {}), + device, + }; + } + + #[allow(dead_code)] + #[inline(always)] + pub fn device(&self) -> &Arc { + &self.device + } + + /// 初始化设备 + fn init_device(&self) -> Result<(), SystemError> { + return Ok(()); // todo + } +} + +#[derive(Debug)] +struct InnerFbConsoleManager {} + +#[derive(Debug)] +struct InnerFbConsoleDevice { + kernfs_inode: Option>, + parent: Option>, + kset: Option>, + bus: Option>, + driver: Option>, + ktype: Option<&'static dyn KObjType>, +} + +/// `/sys/class/graphics/fbcon`代表的 framebuffer console 设备 +#[derive(Debug)] +#[cast_to([sync] Device)] +pub struct FbConsoleDevice { + inner: SpinLock, + kobj_state: LockedKObjectState, +} + +impl FbConsoleDevice { + const NAME: &'static str = "fbcon"; + + pub fn new() -> Arc { + return Arc::new(Self { + inner: SpinLock::new(InnerFbConsoleDevice { + kernfs_inode: None, + parent: None, + kset: None, + bus: None, + ktype: None, + driver: None, + }), + kobj_state: LockedKObjectState::new(None), + }); + } +} + +impl KObject for FbConsoleDevice { + fn as_any_ref(&self) -> &dyn core::any::Any { + self + } + + fn set_inode(&self, inode: Option>) { + self.inner.lock().kernfs_inode = inode; + } + + fn inode(&self) -> Option> { + self.inner.lock().kernfs_inode.clone() + } + + fn parent(&self) -> Option> { + self.inner.lock().parent.clone() + } + + fn set_parent(&self, parent: Option>) { + self.inner.lock().parent = parent; + } + + fn kset(&self) -> Option> { + self.inner.lock().kset.clone() + } + + fn set_kset(&self, kset: Option>) { + 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) { + // 不允许修改 + kwarn!("fbcon name can not be changed"); + } + + fn kobj_state(&self) -> RwLockReadGuard { + self.kobj_state.read() + } + + fn kobj_state_mut(&self) -> RwLockWriteGuard { + self.kobj_state.write() + } + + fn set_kobj_state(&self, state: KObjectState) { + *self.kobj_state.write() = state; + } +} +impl Device for FbConsoleDevice { + fn dev_type(&self) -> DeviceType { + DeviceType::Char + } + + fn id_table(&self) -> IdTable { + IdTable::new(Self::NAME.to_string(), None) + } + + fn set_bus(&self, bus: Option>) { + self.inner.lock().bus = bus; + } + + fn set_class(&self, _class: Option>) { + // 不允许修改 + kwarn!("fbcon's class can not be changed"); + } + + fn class(&self) -> Option> { + sys_class_graphics_instance().map(|ins| ins.clone() as Arc) + } + + fn driver(&self) -> Option> { + self.inner + .lock() + .driver + .clone() + .and_then(|driver| driver.upgrade()) + } + + fn set_driver(&self, driver: Option>) { + self.inner.lock().driver = driver; + } + + fn is_dead(&self) -> bool { + todo!() + } + + fn can_match(&self) -> bool { + todo!() + } + + fn set_can_match(&self, _can_match: bool) { + todo!() + } + + fn state_synced(&self) -> bool { + todo!() + } + + fn attribute_groups(&self) -> Option<&'static [&'static dyn AttributeGroup]> { + return Some(&[&AnonymousAttributeGroup]); + } +} + +/// framebuffer console设备的匿名属性组 +#[derive(Debug)] +struct AnonymousAttributeGroup; + +impl AttributeGroup for AnonymousAttributeGroup { + fn name(&self) -> Option<&str> { + None + } + + fn attrs(&self) -> &[&'static dyn Attribute] { + return &[&AttrRotate, &AttrRotateAll, &AttrCursorBlink]; + } + + fn is_visible( + &self, + _kobj: Arc, + attr: &'static dyn Attribute, + ) -> Option { + return Some(attr.mode()); + } +} + +#[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 + } + + /// https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/video/fbdev/core/fbcon.c#3226 + fn show(&self, _kobj: Arc, buf: &mut [u8]) -> Result { + kwarn!("fbcon rotate show not implemented"); + return sysfs_emit_str(buf, "0\n"); + } + + /// https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/video/fbdev/core/fbcon.c#3182 + fn store(&self, _kobj: Arc, _buf: &[u8]) -> Result { + kwarn!("fbcon rotate store not implemented"); + return Err(SystemError::ENOSYS); + } +} + +#[derive(Debug)] +struct AttrRotateAll; + +impl Attribute for AttrRotateAll { + fn name(&self) -> &str { + "rotate_all" + } + + fn mode(&self) -> ModeType { + ModeType::S_IWUSR + } + + fn support(&self) -> SysFSOpsSupport { + SysFSOpsSupport::STORE + } + + /// https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/video/fbdev/core/fbcon.c#3204 + fn store(&self, _kobj: Arc, _buf: &[u8]) -> Result { + kwarn!("fbcon rotate_all store not implemented"); + return Err(SystemError::ENOSYS); + } +} + +#[derive(Debug)] +struct AttrCursorBlink; + +impl Attribute for AttrCursorBlink { + fn name(&self) -> &str { + "cursor_blink" + } + + 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/fbcon.c#3245 + fn show(&self, _kobj: Arc, _buf: &mut [u8]) -> Result { + todo!() + } + + fn store(&self, _kobj: Arc, _buf: &[u8]) -> Result { + todo!() + } +} diff --git a/kernel/src/driver/video/fbdev/base/fbmem.rs b/kernel/src/driver/video/fbdev/base/fbmem.rs new file mode 100644 index 00000000..3a4e6912 --- /dev/null +++ b/kernel/src/driver/video/fbdev/base/fbmem.rs @@ -0,0 +1,77 @@ +use alloc::{ + string::ToString, + sync::{Arc, Weak}, +}; + +use crate::{ + driver::base::{ + class::{class_manager, Class}, + device::sys_dev_char_kset, + kobject::KObject, + subsys::SubSysPrivate, + }, + syscall::SystemError, +}; + +use super::fbcon::fb_console_init; + +/// `/sys/class/graphics` 的 class 实例 +static mut CLASS_GRAPHICS_INSTANCE: Option> = None; + +/// 获取 `/sys/class/graphics` 的 class 实例 +#[inline(always)] +#[allow(dead_code)] +pub fn sys_class_graphics_instance() -> Option<&'static Arc> { + unsafe { CLASS_GRAPHICS_INSTANCE.as_ref() } +} + +/// 初始化帧缓冲区子系统 +pub fn fbmem_init() -> Result<(), SystemError> { + let graphics_class = GraphicsClass::new(); + class_manager().class_register(&(graphics_class.clone() as Arc))?; + + unsafe { + CLASS_GRAPHICS_INSTANCE = Some(graphics_class); + } + + fb_console_init()?; + return Ok(()); +} + +/// `/sys/class/graphics` 类 +#[derive(Debug)] +pub struct GraphicsClass { + subsystem: SubSysPrivate, +} + +impl GraphicsClass { + const NAME: &'static str = "graphics"; + pub fn new() -> Arc { + let r = Self { + subsystem: SubSysPrivate::new(Self::NAME.to_string(), None, None, &[]), + }; + let r = Arc::new(r); + r.subsystem() + .set_class(Some(Arc::downgrade(&r) as Weak)); + + return r; + } +} + +impl Class for GraphicsClass { + fn name(&self) -> &'static str { + return Self::NAME; + } + + fn dev_kobj(&self) -> Option> { + Some(sys_dev_char_kset() as Arc) + } + + fn set_dev_kobj(&self, _kobj: Arc) { + unimplemented!("GraphicsClass::set_dev_kobj"); + } + + fn subsystem(&self) -> &SubSysPrivate { + return &self.subsystem; + } +} diff --git a/kernel/src/driver/video/fbdev/base/mod.rs b/kernel/src/driver/video/fbdev/base/mod.rs new file mode 100644 index 00000000..cb81f93f --- /dev/null +++ b/kernel/src/driver/video/fbdev/base/mod.rs @@ -0,0 +1,523 @@ +use alloc::{string::String, sync::Arc}; + +use crate::{ + driver::base::device::Device, + mm::{ucontext::LockedVMA, PhysAddr}, + syscall::SystemError, +}; + +pub mod fbcon; +pub mod fbmem; + +/// 帧缓冲区应该实现的接口 +pub trait FrameBuffer: FrameBufferInfo + FrameBufferOps + Device {} + +/// 帧缓冲区信息 +pub trait FrameBufferInfo { + /// Amount of ioremapped VRAM or 0 + fn screen_size(&self) -> usize; + + /// 获取当前的可变帧缓冲信息 + fn current_fb_var(&self) -> &FbVarScreenInfo; + + /// 获取当前的可变帧缓冲信息(可变引用) + fn current_fb_var_mut(&mut self) -> &mut FbVarScreenInfo; + + /// 获取当前的固定帧缓冲信息 + fn current_fb_fix(&self) -> &FixedScreenInfo; + + /// 获取当前的固定帧缓冲信息(可变引用) + fn current_fb_fix_mut(&mut self) -> &mut FixedScreenInfo; + + /// 获取当前的视频模式 + fn video_mode(&self) -> Option<&FbVideoMode>; +} + +/// 帧缓冲区操作 +/// +/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/fb.h#237 +pub trait FrameBufferOps { + fn fb_open(&self, user: bool); + fn fb_release(&self, user: bool); + + /// 读取帧缓冲区的内容。 + /// + /// 对于具有奇特非线性布局的帧缓冲区或正常内存映射访问无法工作的帧缓冲区,可以使用此方法。 + fn fb_read(&self, _buf: &mut [u8], _pos: usize) -> Result { + Err(SystemError::ENOSYS) + } + + /// 将帧缓冲区的内容写入。 + /// + /// 对于具有奇特非线性布局的帧缓冲区或正常内存映射访问无法工作的帧缓冲区,可以使用此方法。 + fn fb_write(&self, _buf: &[u8], _pos: usize) -> Result { + Err(SystemError::ENOSYS) + } + + /// 设置帧缓冲区的颜色寄存器。 + /// + /// 颜色寄存器的数量和含义取决于帧缓冲区的硬件。 + /// + /// ## 参数 + /// + /// - `regno`:寄存器编号。 + /// - `red`:红色分量。 + /// - `green`:绿色分量。 + /// - `blue`:蓝色分量。 + fn fb_set_color_register( + &self, + regno: u16, + red: u16, + green: u16, + blue: u16, + ) -> Result<(), SystemError>; + + /// 设置帧缓冲区的黑屏模式 + fn fb_blank(&self, blank_mode: BlankMode) -> Result<(), SystemError>; + + /// 在帧缓冲区中绘制一个矩形。 + fn fb_fillrect(&self, _data: FillRectData) -> Result<(), SystemError> { + Err(SystemError::ENOSYS) + } + + /// 将数据从一处复制到另一处。 + fn fb_copyarea(&self, _data: CopyAreaData) -> Result<(), SystemError> { + Err(SystemError::ENOSYS) + } + + /// 将帧缓冲区的内容映射到用户空间。 + fn fb_mmap(&self, _vma: &Arc) -> Result<(), SystemError> { + Err(SystemError::ENOSYS) + } + + /// 卸载与该帧缓冲区相关的所有资源 + fn fb_destroy(&self); +} + +/// 屏幕黑屏模式。 +#[allow(dead_code)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum BlankMode { + /// 取消屏幕黑屏, 垂直同步和水平同步均打开 + Unblank, + /// 屏幕黑屏, 垂直同步和水平同步均打开 + Normal, + /// 屏幕黑屏, 水平同步打开, 垂直同步关闭 + HSync, + /// 屏幕黑屏, 水平同步关闭, 垂直同步打开 + VSync, + /// 屏幕黑屏, 水平同步和垂直同步均关闭 + Powerdown, +} + +/// `FillRectData` 结构体用于表示一个矩形区域并填充特定颜色。 +/// +/// # 结构体字段 +/// * `dx`: +/// * `dy`: +/// * `width`: +/// * `height`: 矩形的高度 +/// * `color`: 用于填充矩形的颜色,是一个32位无符号整数 +/// * `rop`: 光栅操作(Raster Operation),用于定义如何将颜色应用到矩形区域 +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct FillRectData { + /// 矩形左上角的x坐标(相对于屏幕) + pub dx: u32, + /// 矩形左上角的y坐标(相对于屏幕) + pub dy: u32, + /// 矩形的宽度 + pub width: u32, + /// 矩形的高度 + pub height: u32, + /// 用于填充矩形的颜色,是一个32位无符号整数 + pub color: u32, + /// 光栅操作(Raster Operation),用于定义如何将颜色应用到矩形区域 + pub rop: FillRectROP, +} + +impl FillRectData { + #[allow(dead_code)] + pub fn new(dx: u32, dy: u32, width: u32, height: u32, color: u32, rop: FillRectROP) -> Self { + Self { + dx, + dy, + width, + height, + color, + rop, + } + } +} + +/// 光栅操作(Raster Operation),用于定义如何将颜色应用到矩形区域 +#[allow(dead_code)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum FillRectROP { + /// 复制操作,即直接将指定颜色应用到矩形区域,覆盖原有颜色。 + Copy, + /// 异或操作,即将指定颜色与矩形区域原有颜色进行异或操作,结果颜色应用到矩形区域。 + Xor, +} + +/// `CopyAreaData` 结构体用于表示一个矩形区域,并指定从哪个源位置复制数据。 +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct CopyAreaData { + /// 目标矩形左上角的x坐标 + pub dx: u32, + /// 目标矩形左上角的y坐标 + pub dy: u32, + /// 矩形的宽度 + pub width: u32, + /// 矩形的高度 + pub height: u32, + /// 源矩形左上角的x坐标 + pub sx: u32, + /// 源矩形左上角的y坐标 + pub sy: u32, +} + +impl CopyAreaData { + #[allow(dead_code)] + pub fn new(dx: u32, dy: u32, width: u32, height: u32, sx: u32, sy: u32) -> Self { + Self { + dx, + dy, + width, + height, + sx, + sy, + } + } +} + +/// `FbVarScreenInfo` 结构体用于描述屏幕的各种属性。 +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct FbVarScreenInfo { + /// 可见分辨率的宽度 + pub xres: u32, + /// 可见分辨率的高度 + pub yres: u32, + /// 虚拟分辨率的宽度 + pub xres_virtual: u32, + /// 虚拟分辨率的高度 + pub yres_virtual: u32, + /// 从虚拟到可见分辨率的偏移量(宽度方向) + pub xoffset: u32, + /// 从虚拟到可见分辨率的偏移量(高度方向) + pub yoffset: u32, + /// 每像素的位数 + pub bits_per_pixel: u32, + /// 颜色模式 + pub color_mode: FbColorMode, + /// 红色位域 + pub red: FbBitfield, + /// 绿色位域 + pub green: FbBitfield, + /// 蓝色位域 + pub blue: FbBitfield, + /// 透明度位域 + pub transp: FbBitfield, + /// 像素格式 + pub pixel_format: FbPixelFormat, + /// 激活标志(参见FB_ACTIVATE_*) + pub activate: FbActivateFlags, + /// 帧缓冲区的高度(像素) + pub height: u32, + /// 帧缓冲区的宽度(像素) + pub width: u32, + /// 像素时钟(皮秒) + pub pixclock: u32, + /// 左边距 + pub left_margin: u32, + /// 右边距 + pub right_margin: u32, + /// 上边距 + pub upper_margin: u32, + /// 下边距 + pub lower_margin: u32, + /// 水平同步的长度 + pub hsync_len: u32, + /// 垂直同步的长度 + pub vsync_len: u32, + /// 同步标志(参见FB_SYNC_*) + pub sync: FbSyncFlags, + /// 视频模式(参见FB_VMODE_*) + pub vmode: FbVModeFlags, + /// 逆时针旋转的角度 + pub rotate_angle: u32, + /// 颜色空间 + pub colorspace: V4l2Colorspace, +} + +#[allow(dead_code)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum FbColorMode { + /// 灰度 + GrayScale, + /// 彩色 + Color, + /// FOURCC + FourCC, +} + +/// `FbBitfield` 结构体用于描述颜色字段的位域。 +/// +/// 所有的偏移量都是从右边开始,位于一个精确为'bits_per_pixel'宽度的"像素"值内。 +/// 一个像素之后是一个位流,并且未经修改地写入视频内存。 +/// +/// 对于伪颜色:所有颜色组件的偏移和长度应该相同。 +/// 偏移指定了调色板索引在像素值中的最低有效位的位置。 +/// 长度表示可用的调色板条目的数量(即条目数 = 1 << 长度)。 +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct FbBitfield { + /// 位域的起始位置 + pub offset: u32, + /// 位域的长度 + pub length: u32, + /// 最高有效位是否在右边 + pub msb_right: bool, +} + +impl FbBitfield { + #[allow(dead_code)] + pub fn new(offset: u32, length: u32, msb_right: bool) -> Self { + Self { + offset, + length, + msb_right, + } + } +} + +bitflags! { + /// `FbActivateFlags` 用于描述帧缓冲区的激活标志。 + /// + /// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/include/uapi/linux/fb.h#198 + pub struct FbActivateFlags: u32 { + /// 立即设置值(或vbl) + const FB_ACTIVATE_NOW = 0; + /// 在下一次打开时激活 + const FB_ACTIVATE_NXTOPEN = 1; + /// don't set, round up impossible values + const FB_ACTIVATE_TEST = 2; + const FB_ACTIVATE_MASK = 15; + + /// 在下一个vbl上激活值 + const FB_ACTIVATE_VBL = 16; + /// 在vbl上更改色彩映射 + const FB_ACTIVATE_CHANGE_CMAP_VBL = 32; + /// 更改此fb上的所有VC + const FB_ACTIVATE_ALL = 64; + /// 即使没有变化也强制应用 + const FB_ACTIVATE_FORCE = 128; + /// 使视频模式无效 + const FB_ACTIVATE_INV_MODE = 256; + /// 用于KDSET vt ioctl + const FB_ACTIVATE_KD_TEXT = 512; + } +} + +#[allow(dead_code)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum FbPixelFormat { + Standard, + /// Hold And Modify + HAM, + /// order of pixels in each byte is reversed + Reserved, +} + +bitflags! { + pub struct FbSyncFlags: u32 { + /// 水平同步高电平有效 + const FB_SYNC_HOR_HIGH_ACT = 1; + /// 垂直同步高电平有效 + const FB_SYNC_VERT_HIGH_ACT = 2; + /// 外部同步 + const FB_SYNC_EXT = 4; + /// 复合同步高电平有效 + const FB_SYNC_COMP_HIGH_ACT = 8; + /// 广播视频时序 + const FB_SYNC_BROADCAST = 16; + /// sync on green + const FB_SYNC_ON_GREEN = 32; + } +} + +bitflags! { + /// `FbVModeFlags` 用于描述帧缓冲区的视频模式。 + pub struct FbVModeFlags: u32 { + /// 非交错 + const FB_VMODE_NONINTERLACED = 0; + /// 交错 + const FB_VMODE_INTERLACED = 1; + /// 双扫描 + const FB_VMODE_DOUBLE = 2; + /// 交错:首先是顶行 + const FB_VMODE_ODD_FLD_FIRST = 4; + /// 掩码 + const FB_VMODE_MASK = 255; + /// ywrap代替平移 + const FB_VMODE_YWRAP = 256; + /// 平滑xpan可能(内部使用) + const FB_VMODE_SMOOTH_XPAN = 512; + /// 不更新x/yoffset + const FB_VMODE_CONUPDATE = 512; + } +} + +/// 视频颜色空间 +#[allow(dead_code)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum V4l2Colorspace { + /// 默认颜色空间,即让驱动程序自行判断。只能用于视频捕获。 + Default = 0, + /// SMPTE 170M:用于广播NTSC/PAL SDTV + Smpte170m = 1, + /// 过时的1998年前的SMPTE 240M HDTV标准,已被Rec 709取代 + Smpte240m = 2, + /// Rec.709:用于HDTV + Rec709 = 3, + /// 已弃用,不要使用。没有驱动程序会返回这个。这是基于对bt878数据表的误解。 + Bt878 = 4, + /// NTSC 1953颜色空间。只有在处理非常非常旧的NTSC录音时才有意义。已被SMPTE 170M取代。 + System470M = 5, + /// EBU Tech 3213 PAL/SECAM颜色空间。 + System470Bg = 6, + /// 实际上是V4L2_COLORSPACE_SRGB,V4L2_YCBCR_ENC_601和V4L2_QUANTIZATION_FULL_RANGE的简写。用于(Motion-)JPEG。 + Jpeg = 7, + /// 用于RGB颜色空间,如大多数网络摄像头所产生的。 + Srgb = 8, + /// opRGB颜色空间 + Oprgb = 9, + /// BT.2020颜色空间,用于UHDTV。 + Bt2020 = 10, + /// Raw颜色空间:用于RAW未处理的图像 + Raw = 11, + /// DCI-P3颜色空间,用于电影投影机 + DciP3 = 12, + + /// Largest supported colorspace value, assigned by the compiler, used + /// by the framework to check for invalid values. + Last, +} + +impl Default for V4l2Colorspace { + fn default() -> Self { + V4l2Colorspace::Default + } +} + +/// `FixedScreenInfo` 结构体用于描述屏幕的固定属性。 +#[allow(dead_code)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct FixedScreenInfo { + // 字符串,用于标识屏幕,例如 "TT Builtin" + pub id: [char; 16], + // 帧缓冲区的起始物理地址 + pub smem_start: PhysAddr, + // 帧缓冲区的长度 + pub smem_len: u32, + // 屏幕类型,参考 FB_TYPE_ + pub fb_type: FbType, + // 用于表示交错平面的小端辅助类型 + pub type_aux: u32, + // 视觉类型,参考 FB_VISUAL_ + pub visual: FbVisual, + // 水平缩放步长,如果无硬件缩放,则为0 + pub xpanstep: u16, + // 垂直缩放步长,如果无硬件缩放,则为0 + pub ypanstep: u16, + // 垂直环绕步长,如果无硬件环绕,则为0 + pub ywrapstep: u16, + // 一行的大小(以字节为单位) + pub line_length: u32, + // 内存映射I/O的起始物理地址 + pub mmio_start: PhysAddr, + // 内存映射I/O的长度 + pub mmio_len: u32, + // 表示驱动器拥有的特定芯片/卡片类型 + pub accel: u32, + // 表示支持的特性,参考 FB_CAP_ + pub capabilities: FbCapability, +} + +/// 帧缓冲类型 +#[allow(dead_code)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum FbType { + /// 压缩像素 + PackedPixels = 0, + /// 非交错平面 + Planes = 1, + /// 交错平面 + InterleavedPlanes = 2, + /// 文本/属性 + Text = 3, + /// EGA/VGA平面 + VgaPlanes = 4, + /// 由V4L2 FOURCC标识的类型 + FourCC = 5, +} + +/// 帧缓冲视觉类型 +#[allow(dead_code)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum FbVisual { + /// 单色。1=黑色 0=白色 + Mono01 = 0, + /// 单色。1=白色 0=黑色 + Mono10 = 1, + /// 真彩色 + TrueColor = 2, + /// 伪彩色(如Atari) + PseudoColor = 3, + /// 直接颜色 + DirectColor = 4, + /// 只读的伪彩色 + StaticPseudoColor = 5, + /// 由FOURCC标识的类型 + FourCC, +} + +#[allow(dead_code)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub enum FbCapability { + Default = 0, + /// 设备支持基于FOURCC的格式。 + FourCC, +} + +/// 视频模式 +#[allow(dead_code)] +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct FbVideoMode { + /// 可选的名称 + pub name: Option, + /// 可选的刷新率 + pub refresh: Option, + /// 水平分辨率 + pub xres: u32, + /// 垂直分辨率 + pub yres: u32, + /// 像素时钟 + pub pixclock: u32, + /// 左边距 + pub left_margin: u32, + /// 右边距 + pub right_margin: u32, + /// 上边距 + pub upper_margin: u32, + /// 下边距 + pub lower_margin: u32, + /// 水平同步长度 + pub hsync_len: u32, + /// 垂直同步长度 + pub vsync_len: u32, + /// 同步 + pub sync: FbSyncFlags, + /// 视频模式 + pub vmode: FbVModeFlags, + /// 标志 + pub flag: u32, +} diff --git a/kernel/src/driver/video/fbdev/mod.rs b/kernel/src/driver/video/fbdev/mod.rs new file mode 100644 index 00000000..6cf245d4 --- /dev/null +++ b/kernel/src/driver/video/fbdev/mod.rs @@ -0,0 +1 @@ +pub mod base; diff --git a/kernel/src/driver/video/mod.rs b/kernel/src/driver/video/mod.rs index e8462c00..f8d5074f 100644 --- a/kernel/src/driver/video/mod.rs +++ b/kernel/src/driver/video/mod.rs @@ -28,6 +28,8 @@ use crate::{ time::timer::{Timer, TimerFunction}, }; +pub mod fbdev; + static mut __MAMAGER: Option = None; pub fn video_refresh_manager() -> &'static VideoRefreshManager {