mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
实现了rtc的抽象,并且把x86的cmos rtc接入到设备驱动模型 (#674)
* 实现了rtc的抽象,并且把x86的cmos rtc接入到设备驱动模型。
This commit is contained in:
parent
597ecc08c2
commit
da15231979
@ -31,6 +31,7 @@ bit_field = "=0.10"
|
||||
bitfield-struct = "=0.5.3"
|
||||
bitflags = "=1.3.2"
|
||||
bitmap = { path = "crates/bitmap" }
|
||||
driver_base_macros = { "path" = "crates/driver_base_macros" }
|
||||
# 一个no_std的hashmap、hashset
|
||||
elf = { version = "=0.7.2", default-features = false }
|
||||
hashbrown = "=0.13.2"
|
||||
|
8
kernel/crates/driver_base_macros/Cargo.toml
Normal file
8
kernel/crates/driver_base_macros/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "driver_base_macros"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
20
kernel/crates/driver_base_macros/src/lib.rs
Normal file
20
kernel/crates/driver_base_macros/src/lib.rs
Normal file
@ -0,0 +1,20 @@
|
||||
#![no_std]
|
||||
|
||||
/// 获取指定字段
|
||||
///
|
||||
/// 当weak指针的strong count为0的时候,清除弱引用
|
||||
#[macro_export]
|
||||
macro_rules! get_weak_or_clear {
|
||||
($field:expr) => {{
|
||||
if let Some(x) = $field.clone() {
|
||||
if x.strong_count() == 0 {
|
||||
$field = None;
|
||||
None
|
||||
} else {
|
||||
Some(x)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}};
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
pub mod apic;
|
||||
pub mod hpet;
|
||||
pub mod rtc;
|
||||
pub mod tsc;
|
||||
pub mod video;
|
||||
|
312
kernel/src/arch/x86_64/driver/rtc.rs
Normal file
312
kernel/src/arch/x86_64/driver/rtc.rs
Normal file
@ -0,0 +1,312 @@
|
||||
use core::any::Any;
|
||||
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use system_error::SystemError;
|
||||
use unified_init::macros::unified_init;
|
||||
|
||||
use crate::{
|
||||
arch::{io::PortIOArch, CurrentIrqArch, CurrentPortIOArch},
|
||||
driver::{
|
||||
base::{
|
||||
class::Class,
|
||||
device::{
|
||||
bus::Bus, device_manager, driver::Driver, Device, DeviceCommonData, DeviceState,
|
||||
DeviceType, IdTable,
|
||||
},
|
||||
kobject::{KObjType, KObject, KObjectCommonData, KObjectState, LockedKObjectState},
|
||||
kset::KSet,
|
||||
platform::platform_device::{platform_device_manager, PlatformDevice},
|
||||
},
|
||||
rtc::{RtcClassOps, RtcDevice, RtcTime},
|
||||
},
|
||||
exception::InterruptArch,
|
||||
filesystem::kernfs::KernFSInode,
|
||||
init::initcall::INITCALL_DEVICE,
|
||||
kerror,
|
||||
libs::{
|
||||
mutex::Mutex,
|
||||
rwlock::{RwLockReadGuard, RwLockWriteGuard},
|
||||
spinlock::{SpinLock, SpinLockGuard},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cast_to([sync] Device, PlatformDevice, RtcDevice)]
|
||||
struct CmosRtcDevice {
|
||||
inner: SpinLock<InnerCmosRtc>,
|
||||
locked_kobjstate: LockedKObjectState,
|
||||
ops_mutex: Mutex<()>,
|
||||
}
|
||||
|
||||
impl CmosRtcDevice {
|
||||
const NAME: &str = "rtc_cmos";
|
||||
pub fn new() -> Arc<Self> {
|
||||
let r = CmosRtcDevice {
|
||||
inner: SpinLock::new(InnerCmosRtc {
|
||||
device_common: DeviceCommonData::default(),
|
||||
kobject_common: KObjectCommonData::default(),
|
||||
device_state: DeviceState::NotInitialized,
|
||||
}),
|
||||
locked_kobjstate: LockedKObjectState::new(None),
|
||||
ops_mutex: Mutex::new(()),
|
||||
};
|
||||
|
||||
r.inner().device_common.can_match = true;
|
||||
|
||||
Arc::new(r)
|
||||
}
|
||||
|
||||
fn inner(&self) -> SpinLockGuard<InnerCmosRtc> {
|
||||
self.inner.lock()
|
||||
}
|
||||
|
||||
///置位0x70的第7位,禁止不可屏蔽中断
|
||||
#[inline]
|
||||
fn read_cmos(&self, addr: u8) -> u8 {
|
||||
unsafe {
|
||||
CurrentPortIOArch::out8(0x70, 0x80 | addr);
|
||||
return CurrentPortIOArch::in8(0x71);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct InnerCmosRtc {
|
||||
device_common: DeviceCommonData,
|
||||
kobject_common: KObjectCommonData,
|
||||
|
||||
device_state: DeviceState,
|
||||
}
|
||||
|
||||
impl RtcDevice for CmosRtcDevice {
|
||||
fn class_ops(&self) -> &'static dyn RtcClassOps {
|
||||
&CmosRtcClassOps
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformDevice for CmosRtcDevice {
|
||||
fn pdev_name(&self) -> &str {
|
||||
Self::NAME
|
||||
}
|
||||
|
||||
fn set_pdev_id(&self, _id: i32) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_pdev_id_auto(&self, _id_auto: bool) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn is_initialized(&self) -> bool {
|
||||
self.inner().device_state == DeviceState::Initialized
|
||||
}
|
||||
|
||||
fn set_state(&self, set_state: DeviceState) {
|
||||
self.inner().device_state = set_state;
|
||||
}
|
||||
}
|
||||
|
||||
impl Device for CmosRtcDevice {
|
||||
fn dev_type(&self) -> DeviceType {
|
||||
DeviceType::Rtc
|
||||
}
|
||||
|
||||
fn id_table(&self) -> IdTable {
|
||||
IdTable::new(Self::NAME.to_string(), None)
|
||||
}
|
||||
|
||||
fn set_bus(&self, bus: Option<Weak<dyn Bus>>) {
|
||||
self.inner().device_common.bus = bus;
|
||||
}
|
||||
|
||||
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(|c| c.upgrade())
|
||||
}
|
||||
|
||||
fn driver(&self) -> Option<Arc<dyn Driver>> {
|
||||
self.inner()
|
||||
.device_common
|
||||
.get_driver_weak_or_clear()
|
||||
.and_then(|d| d.upgrade())
|
||||
}
|
||||
|
||||
fn set_driver(&self, driver: Option<Weak<dyn Driver>>) {
|
||||
self.inner().device_common.driver = driver;
|
||||
}
|
||||
|
||||
fn is_dead(&self) -> bool {
|
||||
self.inner().device_common.dead
|
||||
}
|
||||
|
||||
fn can_match(&self) -> bool {
|
||||
self.inner().device_common.can_match
|
||||
}
|
||||
|
||||
fn set_can_match(&self, can_match: bool) {
|
||||
self.inner().device_common.can_match = can_match;
|
||||
}
|
||||
|
||||
fn state_synced(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn bus(&self) -> Option<Weak<dyn Bus>> {
|
||||
self.inner().device_common.get_bus_weak_or_clear()
|
||||
}
|
||||
}
|
||||
|
||||
impl KObject for CmosRtcDevice {
|
||||
fn as_any_ref(&self) -> &dyn 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.get_parent_or_clear_weak()
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CmosRtcClassOps;
|
||||
|
||||
impl RtcClassOps for CmosRtcClassOps {
|
||||
fn read_time(&self, dev: &Arc<dyn RtcDevice>) -> Result<RtcTime, SystemError> {
|
||||
// 检查是否为cmos rtc
|
||||
let dev = dev
|
||||
.as_any_ref()
|
||||
.downcast_ref::<CmosRtcDevice>()
|
||||
.ok_or(SystemError::EINVAL)?;
|
||||
|
||||
let _guard = dev.ops_mutex.lock();
|
||||
|
||||
// 为防止中断请求打断该过程,需要先关中断
|
||||
let irq_guard = unsafe { CurrentIrqArch::save_and_disable_irq() };
|
||||
//0x0B
|
||||
let status_register_b: u8 = dev.read_cmos(0x0B); // 读取状态寄存器B
|
||||
let is_24h: bool = (status_register_b & 0x02) != 0;
|
||||
// 判断是否启用24小时模式
|
||||
let is_binary: bool = (status_register_b & 0x04) != 0; // 判断是否为二进制码
|
||||
let mut res = RtcTime::default();
|
||||
|
||||
loop {
|
||||
res.year = dev.read_cmos(CMOSTimeSelector::Year as u8) as i32;
|
||||
res.month = dev.read_cmos(CMOSTimeSelector::Month as u8) as i32;
|
||||
res.mday = dev.read_cmos(CMOSTimeSelector::Day as u8) as i32;
|
||||
res.hour = dev.read_cmos(CMOSTimeSelector::Hour as u8) as i32;
|
||||
res.minute = dev.read_cmos(CMOSTimeSelector::Minute as u8) as i32;
|
||||
res.second = dev.read_cmos(CMOSTimeSelector::Second as u8) as i32;
|
||||
|
||||
if res.second == dev.read_cmos(CMOSTimeSelector::Second as u8) as i32 {
|
||||
break;
|
||||
} // 若读取时间过程中时间发生跳变则重新读取
|
||||
}
|
||||
|
||||
unsafe {
|
||||
CurrentPortIOArch::out8(0x70, 0x00);
|
||||
}
|
||||
|
||||
if !is_binary
|
||||
// 把BCD转为二进制
|
||||
{
|
||||
res.second = (res.second & 0xf) + (res.second >> 4) * 10;
|
||||
res.minute = (res.minute & 0xf) + (res.minute >> 4) * 10;
|
||||
res.hour = ((res.hour & 0xf) + ((res.hour & 0x70) >> 4) * 10) | (res.hour & 0x80);
|
||||
res.mday = (res.mday & 0xf) + ((res.mday / 16) * 10);
|
||||
res.month = (res.month & 0xf) + (res.month >> 4) * 10;
|
||||
res.year = (res.year & 0xf) + (res.year >> 4) * 10;
|
||||
}
|
||||
res.year += 100;
|
||||
|
||||
if (!is_24h) && (res.hour & 0x80) != 0 {
|
||||
res.hour = ((res.hour & 0x7f) + 12) % 24;
|
||||
} // 将十二小时制转为24小时
|
||||
|
||||
res.month -= 1;
|
||||
|
||||
drop(irq_guard);
|
||||
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
fn set_time(&self, _dev: &Arc<dyn RtcDevice>, _time: &RtcTime) -> Result<(), SystemError> {
|
||||
kerror!("set_time is not implemented for CmosRtcClassOps");
|
||||
Err(SystemError::ENOSYS)
|
||||
}
|
||||
}
|
||||
|
||||
/// used in the form of u8
|
||||
#[repr(u8)]
|
||||
enum CMOSTimeSelector {
|
||||
Second = 0x00,
|
||||
Minute = 0x02,
|
||||
Hour = 0x04,
|
||||
Day = 0x07,
|
||||
Month = 0x08,
|
||||
Year = 0x09,
|
||||
}
|
||||
|
||||
#[unified_init(INITCALL_DEVICE)]
|
||||
pub fn cmos_rtc_device_init() -> Result<(), SystemError> {
|
||||
let device = CmosRtcDevice::new();
|
||||
device_manager().device_default_initialize(&(device.clone() as Arc<dyn Device>));
|
||||
platform_device_manager().device_add(device)?;
|
||||
|
||||
return Ok(());
|
||||
}
|
@ -404,10 +404,13 @@ impl VirtAddr {
|
||||
}
|
||||
|
||||
unsafe fn allocator_init() {
|
||||
let virt_offset = BOOTSTRAP_MM_INFO.unwrap().start_brk;
|
||||
let phy_offset =
|
||||
unsafe { MMArch::virt_2_phys(VirtAddr::new(page_align_up(virt_offset))) }.unwrap();
|
||||
let virt_offset = VirtAddr::new(page_align_up(BOOTSTRAP_MM_INFO.unwrap().start_brk));
|
||||
|
||||
let phy_offset = unsafe { MMArch::virt_2_phys(virt_offset) }.unwrap();
|
||||
|
||||
mem_block_manager()
|
||||
.reserve_block(PhysAddr::new(0), phy_offset.data())
|
||||
.expect("Failed to reserve block");
|
||||
let mut bump_allocator = BumpAllocator::<X86_64MMArch>::new(phy_offset.data());
|
||||
kdebug!(
|
||||
"BumpAllocator created, offset={:?}",
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ pub mod timeconv;
|
||||
pub mod timekeep;
|
||||
pub mod timekeeping;
|
||||
pub mod timer;
|
||||
|
||||
/* Time structures. (Partitially taken from smoltcp)
|
||||
|
||||
The `time` module contains structures used to represent both
|
||||
@ -124,6 +125,61 @@ pub struct Instant {
|
||||
impl Instant {
|
||||
pub const ZERO: Instant = Instant::from_micros_const(0);
|
||||
|
||||
/// mktime64 - 将日期转换为秒。
|
||||
///
|
||||
/// ## 参数
|
||||
///
|
||||
/// - year0: 要转换的年份
|
||||
/// - mon0: 要转换的月份
|
||||
/// - day: 要转换的天
|
||||
/// - hour: 要转换的小时
|
||||
/// - min: 要转换的分钟
|
||||
/// - sec: 要转换的秒
|
||||
///
|
||||
/// 将公历日期转换为1970-01-01 00:00:00以来的秒数。
|
||||
/// 假设输入为正常的日期格式,即1980-12-31 23:59:59 => 年份=1980, 月=12, 日=31, 时=23, 分=59, 秒=59。
|
||||
///
|
||||
/// [For the Julian calendar(俄罗斯在1917年之前使用,英国及其殖民地在大西洋1752年之前使用,
|
||||
/// 其他地方在1582年之前使用,某些社区仍然在使用)省略-year/100+year/400项,
|
||||
/// 并在结果上加10。]
|
||||
///
|
||||
/// 这个算法最初由高斯(我认为是)发表。
|
||||
///
|
||||
/// 要表示闰秒,可以通过将sec设为60(在ISO 8601允许)来调用此函数。
|
||||
/// 闰秒与随后的秒一样处理,因为它们在UNIX时间中不存在。
|
||||
///
|
||||
/// 支持将午夜作为当日末尾的24:00:00编码 - 即明天的午夜(在ISO 8601允许)。
|
||||
///
|
||||
/// ## 返回
|
||||
///
|
||||
/// 返回:给定输入日期自1970-01-01 00:00:00以来的秒数
|
||||
pub fn mktime64(year0: u32, mon0: u32, day: u32, hour: u32, min: u32, sec: u32) -> Self {
|
||||
let mut mon: i64 = mon0.into();
|
||||
let mut year: u64 = year0.into();
|
||||
let day: u64 = day.into();
|
||||
let hour: u64 = hour.into();
|
||||
let min: u64 = min.into();
|
||||
let sec: u64 = sec.into();
|
||||
|
||||
mon -= 2;
|
||||
/* 1..12 -> 11,12,1..10 */
|
||||
if mon <= 0 {
|
||||
/* Puts Feb last since it has leap day */
|
||||
mon += 12;
|
||||
year -= 1;
|
||||
}
|
||||
let mon = mon as u64;
|
||||
|
||||
let secs = ((((year / 4 - year / 100 + year / 400 + 367 * mon / 12 + day) + year * 365
|
||||
- 719499)
|
||||
* 24 + hour) /* now have hours - midnight tomorrow handled here */
|
||||
* 60 + min)/* now have minutes */
|
||||
* 60
|
||||
+ sec; /* finally seconds */
|
||||
|
||||
Self::from_secs(secs as i64)
|
||||
}
|
||||
|
||||
/// Create a new `Instant` from a number of microseconds.
|
||||
pub fn from_micros<T: Into<i64>>(micros: T) -> Instant {
|
||||
Instant {
|
||||
|
@ -1,6 +1,10 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use crate::driver::timers::rtc::rtc::RtcTime;
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::driver::rtc::interface::rtc_read_time_default;
|
||||
|
||||
use super::TimeSpec;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type ktime_t = i64;
|
||||
@ -14,48 +18,16 @@ fn ktime_to_ns(kt: ktime_t) -> i64 {
|
||||
/// @brief 从RTC获取当前时间,然后计算时间戳。
|
||||
/// 时间戳为从UTC+0 1970-01-01 00:00到当前UTC+0时间,所经过的纳秒数。
|
||||
/// 注意,由于当前未引入时区,因此本函数默认时区为UTC+8来计算
|
||||
fn ktime_get_real() -> ktime_t {
|
||||
let mut rtc_time: RtcTime = RtcTime::default();
|
||||
|
||||
{
|
||||
let r = rtc_time.get();
|
||||
// 返回错误码
|
||||
if let Err(e) = r {
|
||||
return e as ktime_t;
|
||||
}
|
||||
}
|
||||
|
||||
let mut day_count: i32 = 0;
|
||||
for year in 1970..rtc_time.year {
|
||||
let leap: bool = (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0);
|
||||
if leap {
|
||||
day_count += 366;
|
||||
} else {
|
||||
day_count += 365;
|
||||
}
|
||||
}
|
||||
for month in 1..rtc_time.month {
|
||||
match month {
|
||||
1 | 3 | 5 | 7 | 8 | 10 | 12 => day_count += 31,
|
||||
2 => day_count += 28,
|
||||
4 | 6 | 9 | 11 => day_count += 30,
|
||||
_ => day_count += 0,
|
||||
}
|
||||
}
|
||||
|
||||
day_count += rtc_time.day - 1;
|
||||
//转换成纳秒
|
||||
let timestamp: ktime_t = day_count as i64 * 86_400_000_000_000i64
|
||||
+ (rtc_time.hour - 8) as i64 * 3_600_000_000_000i64
|
||||
+ rtc_time.minute as i64 * 60_000_000_000i64
|
||||
+ rtc_time.second as i64 * 1_000_000_000u64 as ktime_t;
|
||||
|
||||
return timestamp;
|
||||
fn ktime_get_real() -> Result<ktime_t, SystemError> {
|
||||
let rtc_time = rtc_read_time_default()?;
|
||||
let time_spec: TimeSpec = rtc_time.into();
|
||||
let r = time_spec.tv_sec * 1_000_000_000 + time_spec.tv_nsec;
|
||||
return Ok(r);
|
||||
}
|
||||
|
||||
/// @brief 暴露给外部使用的接口,返回一个时间戳
|
||||
#[inline]
|
||||
pub fn ktime_get_real_ns() -> i64 {
|
||||
let kt: ktime_t = ktime_get_real();
|
||||
let kt: ktime_t = ktime_get_real().unwrap_or(0);
|
||||
return ktime_to_ns(kt);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use alloc::sync::Arc;
|
||||
use core::sync::atomic::{compiler_fence, AtomicBool, AtomicI64, Ordering};
|
||||
use system_error::SystemError;
|
||||
|
||||
use crate::{
|
||||
arch::CurrentIrqArch,
|
||||
@ -207,6 +208,13 @@ pub fn do_gettimeofday() -> PosixTimeval {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn do_settimeofday64(time: TimeSpec) -> Result<(), SystemError> {
|
||||
timekeeper().0.write_irqsave().xtime = time;
|
||||
// todo: 模仿linux,实现时间误差校准。
|
||||
// https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/time/timekeeping.c?fi=do_settimeofday64#1312
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
/// # 初始化timekeeping模块
|
||||
#[inline(never)]
|
||||
pub fn timekeeping_init() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user