mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-19 00:46:31 +00:00
实现了rtc的抽象,并且把x86的cmos rtc接入到设备驱动模型 (#674)
* 实现了rtc的抽象,并且把x86的cmos rtc接入到设备驱动模型。
This commit is contained in:
@ -277,16 +277,14 @@ impl DriverManager {
|
||||
.and_then(|bus| bus.upgrade())
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
for dev in bus.subsystem().devices().iter() {
|
||||
if self.do_driver_attach(dev, driver) {
|
||||
// 匹配成功
|
||||
return Ok(());
|
||||
}
|
||||
self.do_driver_attach(dev, driver);
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/drivers/base/dd.c?fi=driver_attach#1134
|
||||
#[inline(never)]
|
||||
fn do_driver_attach(&self, device: &Arc<dyn Device>, driver: &Arc<dyn Driver>) -> bool {
|
||||
let r = self.match_device(driver, device).unwrap_or(false);
|
||||
if !r {
|
||||
|
@ -109,6 +109,24 @@ pub trait Driver: Sync + Send + Debug + KObject {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct DriverCommonData {
|
||||
pub devices: Vec<Arc<dyn Device>>,
|
||||
pub bus: Option<Weak<dyn Bus>>,
|
||||
}
|
||||
|
||||
impl DriverCommonData {
|
||||
pub fn push_device(&mut self, device: Arc<dyn Device>) {
|
||||
if !self.devices.iter().any(|d| Arc::ptr_eq(d, &device)) {
|
||||
self.devices.push(device);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_device(&mut self, device: &Arc<dyn Device>) {
|
||||
self.devices.retain(|d| !Arc::ptr_eq(d, device));
|
||||
}
|
||||
}
|
||||
|
||||
impl dyn Driver {
|
||||
pub fn allows_async_probing(&self) -> bool {
|
||||
match self.probe_type() {
|
||||
|
@ -201,6 +201,51 @@ impl dyn Device {
|
||||
}
|
||||
}
|
||||
|
||||
/// 实现了Device trait的设备需要拥有的数据
|
||||
#[derive(Debug)]
|
||||
pub struct DeviceCommonData {
|
||||
pub bus: Option<Weak<dyn Bus>>,
|
||||
pub class: Option<Weak<dyn Class>>,
|
||||
pub driver: Option<Weak<dyn Driver>>,
|
||||
pub dead: bool,
|
||||
pub can_match: bool,
|
||||
}
|
||||
|
||||
impl Default for DeviceCommonData {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bus: None,
|
||||
class: None,
|
||||
driver: None,
|
||||
dead: false,
|
||||
can_match: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceCommonData {
|
||||
/// 获取bus字段
|
||||
///
|
||||
/// 当weak指针的strong count为0的时候,清除弱引用
|
||||
pub fn get_bus_weak_or_clear(&mut self) -> Option<Weak<dyn Bus>> {
|
||||
driver_base_macros::get_weak_or_clear!(self.bus)
|
||||
}
|
||||
|
||||
/// 获取class字段
|
||||
///
|
||||
/// 当weak指针的strong count为0的时候,清除弱引用
|
||||
pub fn get_class_weak_or_clear(&mut self) -> Option<Weak<dyn Class>> {
|
||||
driver_base_macros::get_weak_or_clear!(self.class)
|
||||
}
|
||||
|
||||
/// 获取driver字段
|
||||
///
|
||||
/// 当weak指针的strong count为0的时候,清除弱引用
|
||||
pub fn get_driver_weak_or_clear(&mut self) -> Option<Weak<dyn Driver>> {
|
||||
driver_base_macros::get_weak_or_clear!(self.driver)
|
||||
}
|
||||
}
|
||||
|
||||
// 暂定是不可修改的,在初始化的时候就要确定。以后可能会包括例如硬件中断包含的信息
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -4,6 +4,7 @@ use alloc::{
|
||||
string::String,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use driver_base_macros::get_weak_or_clear;
|
||||
use intertrait::CastFromSync;
|
||||
|
||||
use crate::{
|
||||
@ -73,6 +74,21 @@ impl DowncastArc for dyn KObject {
|
||||
}
|
||||
}
|
||||
|
||||
/// kobject的公共数据
|
||||
#[derive(Debug, Default)]
|
||||
pub struct KObjectCommonData {
|
||||
pub kern_inode: Option<Arc<KernFSInode>>,
|
||||
pub parent: Option<Weak<dyn KObject>>,
|
||||
pub kset: Option<Arc<KSet>>,
|
||||
pub kobj_type: Option<&'static dyn KObjType>,
|
||||
}
|
||||
|
||||
impl KObjectCommonData {
|
||||
pub fn get_parent_or_clear_weak(&mut self) -> Option<Weak<dyn KObject>> {
|
||||
get_weak_or_clear!(self.parent)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait KObjType: Debug + Send + Sync {
|
||||
/// 当指定的kobject被释放时,设备驱动模型会调用此方法
|
||||
fn release(&self, _kobj: Arc<dyn KObject>) {}
|
||||
|
@ -61,7 +61,6 @@ pub trait PlatformDevice: Device {
|
||||
/// 设置id是否为自动分配
|
||||
fn set_pdev_id_auto(&self, id_auto: bool);
|
||||
|
||||
fn compatible_table(&self) -> CompatibleTable;
|
||||
/// @brief: 判断设备是否初始化
|
||||
/// @parameter: None
|
||||
/// @return: 如果已经初始化,返回true,否则,返回false
|
||||
|
@ -9,7 +9,7 @@ use crate::{
|
||||
device::{bus::Bus, driver::Driver, Device, DeviceState, DeviceType, IdTable},
|
||||
kobject::{KObjType, KObject, KObjectState, LockedKObjectState},
|
||||
kset::KSet,
|
||||
platform::{platform_device::PlatformDevice, CompatibleTable},
|
||||
platform::platform_device::PlatformDevice,
|
||||
},
|
||||
filesystem::kernfs::KernFSInode,
|
||||
libs::{
|
||||
@ -184,10 +184,6 @@ impl PlatformDevice for I8042PlatformDevice {
|
||||
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
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ pub mod keyboard;
|
||||
pub mod net;
|
||||
pub mod open_firmware;
|
||||
pub mod pci;
|
||||
pub mod rtc;
|
||||
pub mod serial;
|
||||
pub mod timers;
|
||||
pub mod tty;
|
||||
|
109
kernel/src/driver/rtc/class.rs
Normal file
109
kernel/src/driver/rtc/class.rs
Normal file
@ -0,0 +1,109 @@
|
||||
use alloc::{
|
||||
string::ToString,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use system_error::SystemError;
|
||||
use unified_init::macros::unified_init;
|
||||
|
||||
use crate::{
|
||||
driver::base::{
|
||||
class::{class_manager, Class},
|
||||
device::{device_manager, sys_dev_char_kset},
|
||||
kobject::KObject,
|
||||
subsys::SubSysPrivate,
|
||||
},
|
||||
init::initcall::INITCALL_SUBSYS,
|
||||
time::{timekeeping::do_settimeofday64, TimeSpec},
|
||||
};
|
||||
|
||||
use super::{interface::rtc_read_time, register_default_rtc, sysfs::RtcGeneralDevice};
|
||||
|
||||
/// `/sys/class/rtc` 的 class 实例
|
||||
static mut CLASS_RTC_INSTANCE: Option<Arc<RtcClass>> = None;
|
||||
|
||||
/// 获取 `/sys/class/rtc` 的 class 实例
|
||||
#[inline(always)]
|
||||
#[allow(dead_code)]
|
||||
pub fn sys_class_rtc_instance() -> Option<&'static Arc<RtcClass>> {
|
||||
unsafe { CLASS_RTC_INSTANCE.as_ref() }
|
||||
}
|
||||
|
||||
/// 初始化帧缓冲区子系统
|
||||
#[unified_init(INITCALL_SUBSYS)]
|
||||
pub fn fbmem_init() -> Result<(), SystemError> {
|
||||
let rtc_class = RtcClass::new();
|
||||
class_manager().class_register(&(rtc_class.clone() as Arc<dyn Class>))?;
|
||||
|
||||
unsafe {
|
||||
CLASS_RTC_INSTANCE = Some(rtc_class);
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// `/sys/class/rtc` 类
|
||||
#[derive(Debug)]
|
||||
pub struct RtcClass {
|
||||
subsystem: SubSysPrivate,
|
||||
}
|
||||
|
||||
impl RtcClass {
|
||||
const NAME: &'static str = "rtc";
|
||||
pub fn new() -> Arc<Self> {
|
||||
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<dyn Class>));
|
||||
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
impl Class for RtcClass {
|
||||
fn name(&self) -> &'static str {
|
||||
return Self::NAME;
|
||||
}
|
||||
|
||||
fn dev_kobj(&self) -> Option<Arc<dyn KObject>> {
|
||||
Some(sys_dev_char_kset() as Arc<dyn KObject>)
|
||||
}
|
||||
|
||||
fn set_dev_kobj(&self, _kobj: Arc<dyn KObject>) {
|
||||
unimplemented!("RtcClass::set_dev_kobj");
|
||||
}
|
||||
|
||||
fn subsystem(&self) -> &SubSysPrivate {
|
||||
return &self.subsystem;
|
||||
}
|
||||
}
|
||||
|
||||
/// 注册rtc通用设备
|
||||
pub(super) fn rtc_register_device(dev: &Arc<RtcGeneralDevice>) -> Result<(), SystemError> {
|
||||
device_manager().add_device(dev.clone())?;
|
||||
register_default_rtc(dev.clone());
|
||||
// 把硬件时间同步到系统时间
|
||||
rtc_hctosys(dev);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn rtc_hctosys(dev: &Arc<RtcGeneralDevice>) {
|
||||
let r = rtc_read_time(dev);
|
||||
if let Err(e) = r {
|
||||
dev.set_hc2sys_result(Err(e));
|
||||
return;
|
||||
}
|
||||
|
||||
let time = r.unwrap();
|
||||
let timespec64: TimeSpec = time.into();
|
||||
let r = do_settimeofday64(timespec64);
|
||||
dev.set_hc2sys_result(r);
|
||||
|
||||
kinfo!(
|
||||
"Setting system clock to {} {} UTC ({})",
|
||||
time.date_string(),
|
||||
time.time_string(),
|
||||
timespec64.tv_sec
|
||||
);
|
||||
}
|
31
kernel/src/driver/rtc/interface.rs
Normal file
31
kernel/src/driver/rtc/interface.rs
Normal file
@ -0,0 +1,31 @@
|
||||
use alloc::sync::Arc;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::driver::base::kobject::KObject;
|
||||
|
||||
use super::{global_default_rtc, sysfs::RtcGeneralDevice, utils::kobj2rtc_device, RtcTime};
|
||||
|
||||
/// 根据rtc general device, 读取真实时间
|
||||
pub fn rtc_read_time(general_dev: &Arc<RtcGeneralDevice>) -> Result<RtcTime, SystemError> {
|
||||
let class_ops = general_dev.class_ops().ok_or(SystemError::EINVAL)?;
|
||||
|
||||
let real_dev = general_dev
|
||||
.parent()
|
||||
.and_then(|p| p.upgrade())
|
||||
.ok_or(SystemError::ENODEV)?;
|
||||
|
||||
let real_dev = kobj2rtc_device(real_dev).ok_or(SystemError::EINVAL)?;
|
||||
|
||||
let time = class_ops.read_time(&real_dev)?;
|
||||
|
||||
if !time.valid() {
|
||||
return Err(SystemError::EINVAL);
|
||||
}
|
||||
|
||||
return Ok(time);
|
||||
}
|
||||
|
||||
/// 从全局默认的rtc时钟那里读取时间
|
||||
pub fn rtc_read_time_default() -> Result<RtcTime, SystemError> {
|
||||
rtc_read_time(&global_default_rtc().ok_or(SystemError::ENODEV)?)
|
||||
}
|
169
kernel/src/driver/rtc/mod.rs
Normal file
169
kernel/src/driver/rtc/mod.rs
Normal file
@ -0,0 +1,169 @@
|
||||
use core::fmt::Debug;
|
||||
|
||||
use alloc::{string::String, sync::Arc};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
libs::rwlock::RwLock,
|
||||
time::{Instant, TimeSpec, NSEC_PER_SEC},
|
||||
};
|
||||
|
||||
use self::sysfs::RtcGeneralDevice;
|
||||
|
||||
use super::base::device::Device;
|
||||
|
||||
pub mod class;
|
||||
pub mod interface;
|
||||
pub mod rtc_cmos;
|
||||
mod sysfs;
|
||||
mod utils;
|
||||
|
||||
/// 全局默认rtc
|
||||
static GLOBAL_DEFAULT_RTC: RwLock<Option<Arc<RtcGeneralDevice>>> = RwLock::new(None);
|
||||
|
||||
/// 获取全局的默认的rtc
|
||||
fn global_default_rtc() -> Option<Arc<RtcGeneralDevice>> {
|
||||
GLOBAL_DEFAULT_RTC.read().clone()
|
||||
}
|
||||
|
||||
/// 注册默认的rtc
|
||||
fn register_default_rtc(general_device: Arc<RtcGeneralDevice>) -> bool {
|
||||
let upg = GLOBAL_DEFAULT_RTC.upgradeable_read();
|
||||
if let Some(old_dev) = upg.as_ref() {
|
||||
if old_dev.priority() >= general_device.priority() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let mut write = upg.upgrade();
|
||||
|
||||
write.replace(general_device);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// RTC设备的trait
|
||||
pub trait RtcDevice: Device {
|
||||
fn class_ops(&self) -> &'static dyn RtcClassOps;
|
||||
}
|
||||
|
||||
pub trait RtcClassOps: Send + Sync + Debug {
|
||||
fn read_time(&self, dev: &Arc<dyn RtcDevice>) -> Result<RtcTime, SystemError>;
|
||||
fn set_time(&self, dev: &Arc<dyn RtcDevice>, time: &RtcTime) -> Result<(), SystemError>;
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Copy)]
|
||||
pub struct RtcTime {
|
||||
/// `second`: 秒,范围从 0 到 59
|
||||
pub second: i32,
|
||||
/// `minute`: 分钟,范围从 0 到 59
|
||||
pub minute: i32,
|
||||
/// `hour`: 小时,范围从 0 到 23
|
||||
pub hour: i32,
|
||||
/// `mday`: 一个月中的第几天,范围从 1 到 31
|
||||
pub mday: i32,
|
||||
/// `month`: 月份,范围从 0 到 11
|
||||
pub month: i32,
|
||||
/// `year`: 年份(相对于1900年)
|
||||
pub year: i32,
|
||||
/// `wday`: 一周中的第几天,范围从 0(周日)到 6(周六)
|
||||
pub wday: i32,
|
||||
/// `yday`: 一年中的第几天,范围从 1 到 366
|
||||
pub yday: i32,
|
||||
/// `isdst`: 表示是否为夏令时,通常如果是夏令时,此值为正,否则为零或负
|
||||
pub isdst: i32,
|
||||
}
|
||||
|
||||
impl RtcTime {
|
||||
/// 返回一个格式化的日期字符串
|
||||
///
|
||||
/// 例如,如果日期为2021年1月1日,则返回"2021-01-01"
|
||||
pub fn date_string(&self) -> String {
|
||||
format!(
|
||||
"{:04}-{:02}-{:02}",
|
||||
self.year_real(),
|
||||
self.month_real(),
|
||||
self.mday
|
||||
)
|
||||
}
|
||||
|
||||
/// 返回一个格式化的时间字符串
|
||||
///
|
||||
/// 例如,如果时间为12:00:00,则返回"12:00:00"
|
||||
pub fn time_string(&self) -> String {
|
||||
format!("{:02}:{:02}:{:02}", self.hour, self.minute, self.second)
|
||||
}
|
||||
|
||||
pub fn valid(&self) -> bool {
|
||||
!(self.year < 70
|
||||
|| self.year > (i32::MAX - 1900)
|
||||
|| self.month >= 12
|
||||
|| self.month < 0
|
||||
|| self.mday < 1
|
||||
|| self.mday > self.month_days()
|
||||
|| self.hour >= 24
|
||||
|| self.hour < 0
|
||||
|| self.minute >= 60
|
||||
|| self.minute < 0
|
||||
|| self.second >= 60
|
||||
|| self.second < 0)
|
||||
}
|
||||
|
||||
/// 获取当月有多少天
|
||||
pub fn month_days(&self) -> i32 {
|
||||
let days_in_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||
let month = self.month as usize;
|
||||
let mut days = days_in_month[month];
|
||||
|
||||
if month == 1 && self.is_leap_year() {
|
||||
days += 1;
|
||||
}
|
||||
|
||||
days
|
||||
}
|
||||
|
||||
/// 判断当前是否为闰年
|
||||
pub fn is_leap_year(&self) -> bool {
|
||||
let year = self.year + 1900;
|
||||
(year % 4 == 0 && year % 100 != 0) || year % 400 == 0
|
||||
}
|
||||
|
||||
pub fn year_real(&self) -> i32 {
|
||||
self.year + 1900
|
||||
}
|
||||
|
||||
pub fn month_real(&self) -> i32 {
|
||||
self.month + 1
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RtcTime> for TimeSpec {
|
||||
fn from(val: RtcTime) -> Self {
|
||||
let instant = Instant::mktime64(
|
||||
val.year_real() as u32,
|
||||
(val.month + 1) as u32,
|
||||
(val.mday) as u32,
|
||||
val.hour as u32,
|
||||
val.minute as u32,
|
||||
val.second as u32,
|
||||
);
|
||||
|
||||
/* 注意:RTC 仅存储完整的秒数。它是任意的,它存储的是最接近的值还是
|
||||
* 分割秒数截断的值。然而,重要的是我们使用它来存储截断的值。这是因为
|
||||
* 否则在 RTC 同步函数中,需要读取 both xtime.tv_sec 和 xtime.tv_nsec。
|
||||
* 在某些处理器上(例如 ARM),对 >32位的原子读取是不可行的。所以,
|
||||
* 存储最接近的值会减慢同步 API 的速度。因此,这里我们存储截断的值
|
||||
* 并在后面加上 0.5s 的最佳猜测。
|
||||
*/
|
||||
TimeSpec::new(instant.secs(), (NSEC_PER_SEC >> 1).into())
|
||||
}
|
||||
}
|
||||
|
||||
/// 全局默认rtc的优先级
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Default, PartialEq, PartialOrd, Clone, Copy)]
|
||||
pub enum GeneralRtcPriority {
|
||||
#[default]
|
||||
L0 = 0,
|
||||
L1,
|
||||
}
|
227
kernel/src/driver/rtc/rtc_cmos.rs
Normal file
227
kernel/src/driver/rtc/rtc_cmos.rs
Normal file
@ -0,0 +1,227 @@
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
sync::{Arc, Weak},
|
||||
vec::Vec,
|
||||
};
|
||||
use intertrait::cast::CastArc;
|
||||
use system_error::SystemError;
|
||||
use unified_init::macros::unified_init;
|
||||
|
||||
use super::{
|
||||
class::rtc_register_device,
|
||||
sysfs::{rtc_general_device_create, RtcGeneralDevice},
|
||||
RtcClassOps, RtcDevice, RtcTime,
|
||||
};
|
||||
use crate::{
|
||||
driver::base::{
|
||||
device::{
|
||||
bus::Bus,
|
||||
driver::{Driver, DriverCommonData},
|
||||
Device, IdTable,
|
||||
},
|
||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||
kset::KSet,
|
||||
platform::{
|
||||
platform_device::PlatformDevice,
|
||||
platform_driver::{platform_driver_manager, PlatformDriver},
|
||||
},
|
||||
},
|
||||
filesystem::kernfs::KernFSInode,
|
||||
init::initcall::INITCALL_DEVICE,
|
||||
libs::{
|
||||
rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard},
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
},
|
||||
};
|
||||
|
||||
static CMOS_RTC_GENERAL_DEVICE: RwLock<Option<Arc<RtcGeneralDevice>>> = RwLock::new(None);
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cast_to([sync] Driver, PlatformDriver)]
|
||||
struct CmosPlatformDriver {
|
||||
inner: SpinLock<InnerCmosPlatformDriver>,
|
||||
locked_kobjstate: LockedKObjectState,
|
||||
}
|
||||
|
||||
impl CmosPlatformDriver {
|
||||
const NAME: &str = "rtc_cmos";
|
||||
|
||||
fn new() -> Arc<Self> {
|
||||
Arc::new(CmosPlatformDriver {
|
||||
inner: SpinLock::new(InnerCmosPlatformDriver {
|
||||
driver_common: DriverCommonData::default(),
|
||||
kobject_common: KObjectCommonData::default(),
|
||||
}),
|
||||
locked_kobjstate: LockedKObjectState::new(None),
|
||||
})
|
||||
}
|
||||
|
||||
fn inner(&self) -> SpinLockGuard<InnerCmosPlatformDriver> {
|
||||
self.inner.lock()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InnerCmosPlatformDriver {
|
||||
driver_common: DriverCommonData,
|
||||
kobject_common: KObjectCommonData,
|
||||
}
|
||||
|
||||
impl PlatformDriver for CmosPlatformDriver {
|
||||
fn probe(&self, device: &Arc<dyn PlatformDevice>) -> Result<(), SystemError> {
|
||||
let dev = device
|
||||
.clone()
|
||||
.arc_any()
|
||||
.cast::<dyn RtcDevice>()
|
||||
.map_err(|_| SystemError::ENODEV)?;
|
||||
|
||||
if dev.id_table() != self.id_table().unwrap() {
|
||||
return Err(SystemError::ENODEV);
|
||||
}
|
||||
|
||||
if CMOS_RTC_GENERAL_DEVICE.read().is_some() {
|
||||
return Err(SystemError::EBUSY);
|
||||
}
|
||||
|
||||
let mut guard = CMOS_RTC_GENERAL_DEVICE.write();
|
||||
|
||||
// 再次检查
|
||||
if guard.is_some() {
|
||||
return Err(SystemError::EBUSY);
|
||||
}
|
||||
|
||||
let general_rtc_device: Arc<RtcGeneralDevice> = rtc_general_device_create(&dev, None);
|
||||
guard.replace(general_rtc_device.clone());
|
||||
|
||||
general_rtc_device.set_class_ops(&CmosRtcClassOps);
|
||||
drop(guard);
|
||||
|
||||
rtc_register_device(&general_rtc_device)
|
||||
.expect("cmos_rtc: register general rtc device failed");
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
fn remove(&self, _device: &Arc<dyn PlatformDevice>) -> Result<(), SystemError> {
|
||||
// todo: remove
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
|
||||
fn shutdown(&self, _device: &Arc<dyn PlatformDevice>) -> Result<(), SystemError> {
|
||||
unimplemented!("cmos platform driver shutdown")
|
||||
}
|
||||
|
||||
fn suspend(&self, _device: &Arc<dyn PlatformDevice>) -> Result<(), SystemError> {
|
||||
todo!("cmos platform driver suspend")
|
||||
}
|
||||
|
||||
fn resume(&self, _device: &Arc<dyn PlatformDevice>) -> Result<(), SystemError> {
|
||||
todo!("cmos platform driver resume")
|
||||
}
|
||||
}
|
||||
|
||||
impl Driver for CmosPlatformDriver {
|
||||
fn id_table(&self) -> Option<IdTable> {
|
||||
Some(IdTable::new(Self::NAME.to_string(), None))
|
||||
}
|
||||
|
||||
fn devices(&self) -> Vec<Arc<dyn Device>> {
|
||||
self.inner().driver_common.devices.clone()
|
||||
}
|
||||
|
||||
fn add_device(&self, device: Arc<dyn Device>) {
|
||||
self.inner().driver_common.push_device(device);
|
||||
}
|
||||
|
||||
fn delete_device(&self, device: &Arc<dyn Device>) {
|
||||
self.inner().driver_common.delete_device(device);
|
||||
}
|
||||
|
||||
fn set_bus(&self, bus: Option<Weak<dyn Bus>>) {
|
||||
self.inner().driver_common.bus = bus;
|
||||
}
|
||||
|
||||
fn bus(&self) -> Option<Weak<dyn Bus>> {
|
||||
self.inner().driver_common.bus.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl KObject for CmosPlatformDriver {
|
||||
fn as_any_ref(&self) -> &dyn core::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn set_inode(&self, inode: Option<Arc<KernFSInode>>) {
|
||||
self.inner().kobject_common.kern_inode = inode;
|
||||
}
|
||||
|
||||
fn inode(&self) -> Option<Arc<KernFSInode>> {
|
||||
self.inner().kobject_common.kern_inode.clone()
|
||||
}
|
||||
|
||||
fn parent(&self) -> Option<Weak<dyn KObject>> {
|
||||
self.inner().kobject_common.parent.clone()
|
||||
}
|
||||
|
||||
fn set_parent(&self, parent: Option<Weak<dyn KObject>>) {
|
||||
self.inner().kobject_common.parent = parent;
|
||||
}
|
||||
|
||||
fn kset(&self) -> Option<Arc<KSet>> {
|
||||
self.inner().kobject_common.kset.clone()
|
||||
}
|
||||
|
||||
fn set_kset(&self, kset: Option<Arc<KSet>>) {
|
||||
self.inner().kobject_common.kset = kset;
|
||||
}
|
||||
|
||||
fn kobj_type(&self) -> Option<&'static dyn KObjType> {
|
||||
self.inner().kobject_common.kobj_type
|
||||
}
|
||||
|
||||
fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) {
|
||||
self.inner().kobject_common.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.locked_kobjstate.read()
|
||||
}
|
||||
|
||||
fn kobj_state_mut(&self) -> RwLockWriteGuard<KObjectState> {
|
||||
self.locked_kobjstate.write()
|
||||
}
|
||||
|
||||
fn set_kobj_state(&self, state: KObjectState) {
|
||||
*self.locked_kobjstate.write() = state;
|
||||
}
|
||||
}
|
||||
|
||||
#[unified_init(INITCALL_DEVICE)]
|
||||
pub fn cmos_rtc_driver_init() -> Result<(), SystemError> {
|
||||
let driver = CmosPlatformDriver::new();
|
||||
|
||||
platform_driver_manager().register(driver)?;
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct CmosRtcClassOps;
|
||||
|
||||
impl RtcClassOps for CmosRtcClassOps {
|
||||
fn read_time(&self, dev: &Arc<dyn RtcDevice>) -> Result<RtcTime, SystemError> {
|
||||
dev.class_ops().read_time(dev)
|
||||
}
|
||||
|
||||
fn set_time(&self, dev: &Arc<dyn RtcDevice>, time: &RtcTime) -> Result<(), SystemError> {
|
||||
dev.class_ops().set_time(dev, time)
|
||||
}
|
||||
}
|
379
kernel/src/driver/rtc/sysfs.rs
Normal file
379
kernel/src/driver/rtc/sysfs.rs
Normal file
@ -0,0 +1,379 @@
|
||||
use alloc::{
|
||||
string::String,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use ida::IdAllocator;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
driver::base::{
|
||||
class::Class,
|
||||
device::{
|
||||
bus::Bus, device_manager, driver::Driver, Device, DeviceCommonData, DeviceType, IdTable,
|
||||
},
|
||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||
kset::KSet,
|
||||
},
|
||||
filesystem::{
|
||||
kernfs::KernFSInode,
|
||||
sysfs::{
|
||||
file::sysfs_emit_str, Attribute, AttributeGroup, SysFSOpsSupport, SYSFS_ATTR_MODE_RO,
|
||||
},
|
||||
vfs::syscall::ModeType,
|
||||
},
|
||||
libs::{
|
||||
rwlock::{RwLockReadGuard, RwLockWriteGuard},
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
},
|
||||
};
|
||||
|
||||
use super::{
|
||||
class::sys_class_rtc_instance,
|
||||
interface::rtc_read_time,
|
||||
utils::{kobj2rtc_device, kobj2rtc_general_device},
|
||||
GeneralRtcPriority, RtcClassOps, RtcDevice,
|
||||
};
|
||||
|
||||
static RTC_GENERAL_DEVICE_IDA: IdAllocator = IdAllocator::new(0, usize::MAX);
|
||||
|
||||
pub(super) const RTC_HCTOSYS_DEVICE: &str = "rtc0";
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cast_to([sync] KObject, Device, RtcDevice)]
|
||||
pub struct RtcGeneralDevice {
|
||||
name: String,
|
||||
id: usize,
|
||||
inner: SpinLock<InnerRtcGeneralDevice>,
|
||||
kobj_state: LockedKObjectState,
|
||||
priority: GeneralRtcPriority,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InnerRtcGeneralDevice {
|
||||
device_common: DeviceCommonData,
|
||||
kobject_common: KObjectCommonData,
|
||||
|
||||
class_ops: Option<&'static dyn RtcClassOps>,
|
||||
/// 上一次调用`rtc_hctosys()`把时间同步到timekeeper的时候的返回值
|
||||
hc2sysfs_result: Result<(), SystemError>,
|
||||
}
|
||||
|
||||
impl RtcGeneralDevice {
|
||||
/// 创建一个新的通用RTC设备实例
|
||||
///
|
||||
/// 注意,由于还需要进行其他的初始化操作,因此这个函数并不是公开的构造函数。
|
||||
fn new(priority: GeneralRtcPriority) -> Arc<Self> {
|
||||
let id = RTC_GENERAL_DEVICE_IDA.alloc().unwrap();
|
||||
let name = format!("rtc{}", id);
|
||||
Arc::new(Self {
|
||||
name,
|
||||
id,
|
||||
inner: SpinLock::new(InnerRtcGeneralDevice {
|
||||
device_common: DeviceCommonData::default(),
|
||||
kobject_common: KObjectCommonData::default(),
|
||||
class_ops: None,
|
||||
hc2sysfs_result: Err(SystemError::ENODEV),
|
||||
}),
|
||||
kobj_state: LockedKObjectState::new(None),
|
||||
priority,
|
||||
})
|
||||
}
|
||||
|
||||
fn inner(&self) -> SpinLockGuard<InnerRtcGeneralDevice> {
|
||||
self.inner.lock()
|
||||
}
|
||||
|
||||
pub fn set_class_ops(&self, class_ops: &'static dyn RtcClassOps) {
|
||||
self.inner().class_ops = Some(class_ops);
|
||||
}
|
||||
|
||||
pub fn class_ops(&self) -> Option<&'static dyn RtcClassOps> {
|
||||
self.inner().class_ops
|
||||
}
|
||||
|
||||
pub fn priority(&self) -> GeneralRtcPriority {
|
||||
self.priority
|
||||
}
|
||||
|
||||
pub(super) fn set_hc2sys_result(&self, val: Result<(), SystemError>) {
|
||||
self.inner().hc2sysfs_result = val;
|
||||
}
|
||||
|
||||
pub(super) fn hc2sysfs_result(&self) -> Result<(), SystemError> {
|
||||
self.inner().hc2sysfs_result.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RtcGeneralDevice {
|
||||
fn drop(&mut self) {
|
||||
RTC_GENERAL_DEVICE_IDA.free(self.id);
|
||||
}
|
||||
}
|
||||
|
||||
impl RtcDevice for RtcGeneralDevice {
|
||||
fn class_ops(&self) -> &'static dyn super::RtcClassOps {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for RtcGeneralDevice {
|
||||
fn dev_type(&self) -> DeviceType {
|
||||
DeviceType::Rtc
|
||||
}
|
||||
|
||||
fn id_table(&self) -> IdTable {
|
||||
IdTable::new(self.name.clone(), None)
|
||||
}
|
||||
|
||||
fn set_bus(&self, bus: Option<Weak<dyn Bus>>) {
|
||||
self.inner().device_common.bus = bus;
|
||||
}
|
||||
|
||||
fn bus(&self) -> Option<Weak<dyn Bus>> {
|
||||
self.inner().device_common.get_bus_weak_or_clear()
|
||||
}
|
||||
|
||||
fn set_class(&self, class: Option<Weak<dyn Class>>) {
|
||||
self.inner().device_common.class = class;
|
||||
}
|
||||
|
||||
fn class(&self) -> Option<Arc<dyn Class>> {
|
||||
self.inner()
|
||||
.device_common
|
||||
.get_class_weak_or_clear()
|
||||
.and_then(|x| x.upgrade())
|
||||
}
|
||||
|
||||
fn driver(&self) -> Option<Arc<dyn Driver>> {
|
||||
self.inner()
|
||||
.device_common
|
||||
.get_driver_weak_or_clear()
|
||||
.and_then(|x| x.upgrade())
|
||||
}
|
||||
|
||||
fn set_driver(&self, driver: Option<Weak<dyn Driver>>) {
|
||||
self.inner().device_common.driver = driver;
|
||||
}
|
||||
|
||||
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(&[&RtcAttrGroup])
|
||||
}
|
||||
}
|
||||
|
||||
impl KObject for RtcGeneralDevice {
|
||||
fn as_any_ref(&self) -> &dyn core::any::Any {
|
||||
self
|
||||
}
|
||||
|
||||
fn set_inode(&self, inode: Option<Arc<KernFSInode>>) {
|
||||
self.inner().kobject_common.kern_inode = inode;
|
||||
}
|
||||
|
||||
fn inode(&self) -> Option<Arc<KernFSInode>> {
|
||||
self.inner().kobject_common.kern_inode.clone()
|
||||
}
|
||||
|
||||
fn parent(&self) -> Option<Weak<dyn KObject>> {
|
||||
self.inner().kobject_common.parent.clone()
|
||||
}
|
||||
|
||||
fn set_parent(&self, parent: Option<Weak<dyn KObject>>) {
|
||||
self.inner().kobject_common.parent = parent;
|
||||
}
|
||||
|
||||
fn kset(&self) -> Option<Arc<KSet>> {
|
||||
self.inner().kobject_common.kset.clone()
|
||||
}
|
||||
|
||||
fn set_kset(&self, kset: Option<Arc<KSet>>) {
|
||||
self.inner().kobject_common.kset = kset;
|
||||
}
|
||||
|
||||
fn kobj_type(&self) -> Option<&'static dyn KObjType> {
|
||||
self.inner().kobject_common.kobj_type
|
||||
}
|
||||
|
||||
fn set_kobj_type(&self, ktype: Option<&'static dyn KObjType>) {
|
||||
self.inner().kobject_common.kobj_type = ktype;
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
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_mut() = state;
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// 用于创建一个通用的RTC设备实例。
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - `real_dev`: 一个对实际RTC设备的引用,这个设备将作为通用RTC设备的父设备。
|
||||
pub fn rtc_general_device_create(
|
||||
real_dev: &Arc<dyn RtcDevice>,
|
||||
priority: Option<GeneralRtcPriority>,
|
||||
) -> Arc<RtcGeneralDevice> {
|
||||
let dev = RtcGeneralDevice::new(priority.unwrap_or_default());
|
||||
device_manager().device_default_initialize(&(dev.clone() as Arc<dyn Device>));
|
||||
dev.set_parent(Some(Arc::downgrade(real_dev) as Weak<dyn KObject>));
|
||||
dev.set_class(Some(Arc::downgrade(
|
||||
&(sys_class_rtc_instance().cloned().unwrap() as Arc<dyn Class>),
|
||||
)));
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct RtcAttrGroup;
|
||||
|
||||
impl AttributeGroup for RtcAttrGroup {
|
||||
fn name(&self) -> Option<&str> {
|
||||
None
|
||||
}
|
||||
|
||||
fn attrs(&self) -> &[&'static dyn Attribute] {
|
||||
&[&AttrName, &AttrDate, &AttrTime, &AttrHcToSys]
|
||||
}
|
||||
|
||||
fn is_visible(
|
||||
&self,
|
||||
_kobj: Arc<dyn KObject>,
|
||||
attr: &'static dyn Attribute,
|
||||
) -> Option<ModeType> {
|
||||
// todo: https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/rtc/sysfs.c#280
|
||||
|
||||
return Some(attr.mode());
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AttrName;
|
||||
|
||||
impl Attribute for AttrName {
|
||||
fn name(&self) -> &str {
|
||||
"name"
|
||||
}
|
||||
|
||||
fn mode(&self) -> ModeType {
|
||||
SYSFS_ATTR_MODE_RO
|
||||
}
|
||||
|
||||
fn support(&self) -> SysFSOpsSupport {
|
||||
SysFSOpsSupport::ATTR_SHOW
|
||||
}
|
||||
|
||||
fn show(&self, kobj: Arc<dyn KObject>, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let rtc_device = kobj
|
||||
.parent()
|
||||
.and_then(|x| x.upgrade())
|
||||
.ok_or(SystemError::ENODEV)?;
|
||||
let rtc_device = kobj2rtc_device(rtc_device).ok_or(SystemError::EINVAL)?;
|
||||
|
||||
let driver_name = rtc_device.driver().ok_or(SystemError::ENODEV)?.name();
|
||||
let device_name = rtc_device.name();
|
||||
sysfs_emit_str(buf, &format!("{} {}\n", driver_name, device_name))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AttrDate;
|
||||
|
||||
impl Attribute for AttrDate {
|
||||
fn name(&self) -> &str {
|
||||
"date"
|
||||
}
|
||||
|
||||
fn mode(&self) -> ModeType {
|
||||
SYSFS_ATTR_MODE_RO
|
||||
}
|
||||
|
||||
fn support(&self) -> SysFSOpsSupport {
|
||||
SysFSOpsSupport::ATTR_SHOW
|
||||
}
|
||||
|
||||
fn show(&self, kobj: Arc<dyn KObject>, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let rtc_device: Arc<RtcGeneralDevice> =
|
||||
kobj2rtc_general_device(kobj).ok_or(SystemError::EINVAL)?;
|
||||
let time = rtc_read_time(&rtc_device)?;
|
||||
sysfs_emit_str(buf, &time.date_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AttrTime;
|
||||
|
||||
impl Attribute for AttrTime {
|
||||
fn name(&self) -> &str {
|
||||
"time"
|
||||
}
|
||||
|
||||
fn mode(&self) -> ModeType {
|
||||
SYSFS_ATTR_MODE_RO
|
||||
}
|
||||
|
||||
fn support(&self) -> SysFSOpsSupport {
|
||||
SysFSOpsSupport::ATTR_SHOW
|
||||
}
|
||||
|
||||
fn show(&self, kobj: Arc<dyn KObject>, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let rtc_device = kobj2rtc_general_device(kobj).ok_or(SystemError::EINVAL)?;
|
||||
let time = rtc_read_time(&rtc_device)?;
|
||||
sysfs_emit_str(buf, &time.time_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AttrHcToSys;
|
||||
|
||||
impl Attribute for AttrHcToSys {
|
||||
fn name(&self) -> &str {
|
||||
"hctosys"
|
||||
}
|
||||
|
||||
fn mode(&self) -> ModeType {
|
||||
SYSFS_ATTR_MODE_RO
|
||||
}
|
||||
|
||||
fn support(&self) -> SysFSOpsSupport {
|
||||
SysFSOpsSupport::ATTR_SHOW
|
||||
}
|
||||
|
||||
fn show(&self, kobj: Arc<dyn KObject>, buf: &mut [u8]) -> Result<usize, SystemError> {
|
||||
let rtc_device = kobj2rtc_general_device(kobj).ok_or(SystemError::EINVAL)?;
|
||||
if rtc_device.hc2sysfs_result().is_ok() && rtc_device.name().eq(RTC_HCTOSYS_DEVICE) {
|
||||
return sysfs_emit_str(buf, "1\n");
|
||||
}
|
||||
|
||||
return sysfs_emit_str(buf, "0\n");
|
||||
}
|
||||
}
|
16
kernel/src/driver/rtc/utils.rs
Normal file
16
kernel/src/driver/rtc/utils.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use alloc::sync::Arc;
|
||||
use intertrait::cast::CastArc;
|
||||
|
||||
use crate::driver::base::kobject::KObject;
|
||||
|
||||
use super::{sysfs::RtcGeneralDevice, RtcDevice};
|
||||
|
||||
#[inline]
|
||||
pub fn kobj2rtc_device(kobj: Arc<dyn KObject>) -> Option<Arc<dyn RtcDevice>> {
|
||||
kobj.arc_any().cast::<dyn RtcDevice>().ok()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn kobj2rtc_general_device(kobj: Arc<dyn KObject>) -> Option<Arc<RtcGeneralDevice>> {
|
||||
kobj.arc_any().downcast().ok()
|
||||
}
|
@ -177,10 +177,6 @@ impl Serial8250ISADevices {
|
||||
}
|
||||
|
||||
impl PlatformDevice for Serial8250ISADevices {
|
||||
fn compatible_table(&self) -> crate::driver::base::platform::CompatibleTable {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn pdev_id(&self) -> (i32, bool) {
|
||||
return (
|
||||
self.id.load(Ordering::SeqCst),
|
||||
|
@ -1,2 +1 @@
|
||||
pub mod hpet;
|
||||
pub mod rtc;
|
||||
|
@ -1,2 +0,0 @@
|
||||
#[allow(clippy::module_inception)]
|
||||
pub mod rtc;
|
@ -1,90 +0,0 @@
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::{io::PortIOArch, CurrentIrqArch, CurrentPortIOArch},
|
||||
exception::InterruptArch,
|
||||
};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RtcTime {
|
||||
pub second: i32,
|
||||
pub minute: i32,
|
||||
pub hour: i32,
|
||||
pub day: i32,
|
||||
pub month: i32,
|
||||
pub year: i32,
|
||||
}
|
||||
|
||||
impl RtcTime {
|
||||
///@brief 从主板cmos中获取时间
|
||||
///
|
||||
///@param self time结构体
|
||||
///@return int 成功则为0
|
||||
pub fn get(&mut self) -> Result<i32, SystemError> {
|
||||
// 为防止中断请求打断该过程,需要先关中断
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
//0x0B
|
||||
let status_register_b: u8 = read_cmos(0x0B); // 读取状态寄存器B
|
||||
let is_24h: bool = (status_register_b & 0x02) != 0;
|
||||
// 判断是否启用24小时模式
|
||||
|
||||
let is_binary: bool = (status_register_b & 0x04) != 0; // 判断是否为二进制码
|
||||
|
||||
loop {
|
||||
self.year = read_cmos(CMOSTimeSelector::Year as u8) as i32;
|
||||
self.month = read_cmos(CMOSTimeSelector::Month as u8) as i32;
|
||||
self.day = read_cmos(CMOSTimeSelector::Day as u8) as i32;
|
||||
self.hour = read_cmos(CMOSTimeSelector::Hour as u8) as i32;
|
||||
self.minute = read_cmos(CMOSTimeSelector::Minute as u8) as i32;
|
||||
self.second = read_cmos(CMOSTimeSelector::Second as u8) as i32;
|
||||
|
||||
if self.second == read_cmos(CMOSTimeSelector::Second as u8) as i32 {
|
||||
break;
|
||||
} // 若读取时间过程中时间发生跳变则重新读取
|
||||
}
|
||||
|
||||
unsafe {
|
||||
CurrentPortIOArch::out8(0x70, 0x00);
|
||||
}
|
||||
|
||||
if !is_binary
|
||||
// 把BCD转为二进制
|
||||
{
|
||||
self.second = (self.second & 0xf) + (self.second >> 4) * 10;
|
||||
self.minute = (self.minute & 0xf) + (self.minute >> 4) * 10;
|
||||
self.hour = ((self.hour & 0xf) + ((self.hour & 0x70) >> 4) * 10) | (self.hour & 0x80);
|
||||
self.day = (self.day & 0xf) + ((self.day / 16) * 10);
|
||||
self.month = (self.month & 0xf) + (self.month >> 4) * 10;
|
||||
self.year = (self.year & 0xf) + (self.year >> 4) * 10;
|
||||
}
|
||||
self.year += 2000;
|
||||
|
||||
if (!is_24h) && (self.hour & 0x80) != 0 {
|
||||
self.hour = ((self.hour & 0x7f) + 12) % 24;
|
||||
} // 将十二小时制转为24小时
|
||||
|
||||
drop(irq_guard);
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
}
|
||||
|
||||
///置位0x70的第7位,禁止不可屏蔽中断
|
||||
#[inline]
|
||||
fn read_cmos(addr: u8) -> u8 {
|
||||
unsafe {
|
||||
CurrentPortIOArch::out8(0x70, 0x80 | addr);
|
||||
return CurrentPortIOArch::in8(0x71);
|
||||
}
|
||||
}
|
||||
|
||||
/// used in the form of u8
|
||||
#[repr(u8)]
|
||||
enum CMOSTimeSelector {
|
||||
Second = 0x00,
|
||||
Minute = 0x02,
|
||||
Hour = 0x04,
|
||||
Day = 0x07,
|
||||
Month = 0x08,
|
||||
Year = 0x09,
|
||||
}
|
@ -26,11 +26,13 @@ lazy_static! {
|
||||
/// 是否已经添加了软光标
|
||||
pub(super) static ref SOFTCURSOR_ORIGINAL: RwLock<Option<VcCursor>> = RwLock::new(None);
|
||||
|
||||
pub static ref CURRENT_VCNUM: AtomicIsize = AtomicIsize::new(-1);
|
||||
|
||||
pub static ref CONSOLE_BLANKED: AtomicBool = AtomicBool::new(false);
|
||||
}
|
||||
|
||||
pub static CURRENT_VCNUM: AtomicIsize = AtomicIsize::new(-1);
|
||||
|
||||
pub static CONSOLE_BLANKED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
/// ## 虚拟控制台的信息
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct VirtualConsoleData {
|
||||
|
@ -25,7 +25,6 @@ use crate::{
|
||||
platform::{
|
||||
platform_device::{platform_device_manager, PlatformDevice},
|
||||
platform_driver::{platform_driver_manager, PlatformDriver},
|
||||
CompatibleTable,
|
||||
},
|
||||
},
|
||||
serial::serial8250::send_to_default_serial8250_port,
|
||||
@ -159,10 +158,6 @@ impl PlatformDevice for VesaFb {
|
||||
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
|
||||
}
|
||||
|
Reference in New Issue
Block a user