前言
当Linux内核启动时,它会从RTC中读取时间与日期,作为基准值。然后通过软件来维护系统时间和日期。Linux系统中提供了RTC核心层,对于驱动开发者而言,操作起来就变得很简单了。我们来看看整体框架。
驱动框架
下面是整体框架图:
与RTC核心有关的文件有:
文件 |
描述 |
/drivers/rtc/class.c |
这个文件向linux设备模型核心注册了一个类RTC,然后向驱动程序提供了注册/注销接口 |
/drivers/rtc/rtc-dev.c |
这个文件定义了基本的设备文件操作函数,如:open,read等 |
/drivers/rtc/interface.c |
这个文件主要提供了用户程序与RTC驱动的接口函数,用户程序一般通过ioctl与RTC驱动交互,这里定义了每个ioctl命令需要调用的函数 |
/drivers/rtc/rtc-sysfs.c |
与sysfs有关 |
/drivers/rtc/rtc-proc.c |
与proc文件系统有关 |
/include/linux/rtc.h |
定义了与RTC有关的数据结构 |
重要结构体
- rtc_device
//RTC设备structrtc_device { structdevicedev; structmodule*owner; intid; conststructrtc_class_ops*ops; //rtc操作函数structmutexops_lock; structcdevchar_dev; unsignedlongflags; unsignedlongirq_data; spinlock_tirq_lock; wait_queue_head_tirq_queue; structfasync_struct*async_queue; intirq_freq; intmax_user_freq; structtimerqueue_headtimerqueue; structrtc_timeraie_timer; structrtc_timeruie_rtctimer; structhrtimerpie_timer; /* sub second exp, so needs hrtimer */intpie_enabled; structwork_structirqwork; /* Some hardware can't support UIE mode */intuie_unsupported; longset_offset_nsec; boolregistered; structnvmem_device*nvmem; /* Old ABI support */boolnvram_old_abi; structbin_attribute*nvram; time64_trange_min; timeu64_trange_max; time64_tstart_secs; time64_toffset_secs; boolset_start_time; structwork_structuie_task; structtimer_listuie_timer; /* Those fields are protected by rtc->irq_lock */unsignedintoldsecs; unsignedintuie_irq_active:1; unsignedintstop_uie_polling:1; unsignedintuie_task_active:1; unsignedintuie_timer_active:1; };
上面的结构体表示一个RTC设备,比较简单,主要就是中断信息,字符设备对象,操作函数等。
- rtc_class_ops
//RTC操作函数structrtc_class_ops { int (*ioctl)(structdevice*, unsignedint, unsignedlong); int (*read_time)(structdevice*, structrtc_time*); int (*set_time)(structdevice*, structrtc_time*); int (*read_alarm)(structdevice*, structrtc_wkalrm*); int (*set_alarm)(structdevice*, structrtc_wkalrm*); int (*proc)(structdevice*, structseq_file*); int (*set_mmss64)(structdevice*, time64_tsecs); int (*set_mmss)(structdevice*, unsignedlongsecs); int (*read_callback)(structdevice*, intdata); int (*alarm_irq_enable)(structdevice*, unsignedintenabled); int (*read_offset)(structdevice*, long*offset); int (*set_offset)(structdevice*, longoffset); };
就是一些设置时间和读取时间,以及闹钟等接口函数。
- rtc_time
//时间结构体structrtc_time { inttm_sec; inttm_min; inttm_hour; inttm_mday; inttm_mon; inttm_year; inttm_wday; inttm_yday; inttm_isdst; };
API函数
// 注册RTC classstaticstructrtc_device*rtc_device_register(constchar*name, structdevice*dev, conststructrtc_class_ops*ops, structmodule*owner) structrtc_device*devm_rtc_device_register(structdevice*dev, constchar*name, conststructrtc_class_ops*ops, structmodule*owner) //注销RTC staticvoidrtc_device_unregister(structrtc_device*rtc) voiddevm_rtc_device_unregister(structdevice*dev, structrtc_device*rtc)
总结
RTC也是字符设备驱动,只是进行了封装,封装完之后我们调用起来其实就很简单了。只要实现好接口函数,填充好结构体,然后进行注册即可。