一.描述rtc相关结构体
1.rtc设备
struct rtc_device //rtc设备
{
struct device dev; //设备文件
struct module *owner; //所有者
int id; //次设备号
char name[RTC_DEVICE_NAME_SIZE]; //rtc设备名
const struct rtc_class_ops *ops; //rtc类操作函数集
struct mutex ops_lock;
struct cdev char_dev; //字符设备
unsigned long flags; //忙标志 (RTC_DEV_BUSY)
unsigned long irq_data; //中断数据
spinlock_t irq_lock;
wait_queue_head_t irq_queue;
struct fasync_struct *async_queue;
struct rtc_task *irq_task; //中断任务
spinlock_t irq_task_lock;
int irq_freq; //中断频率
int max_user_freq; //默认64
};
1.1 同时也定义了一个宏,通过设备文件查找rtc设备
#define to_rtc_device(d) container_of(d, struct rtc_device, dev)
2.rtc类操作函数集
struct rtc_class_ops {
int (*open)(struct device *); //打开
void (*release)(struct device *); //释放
int (*ioctl)(struct device *, unsigned int, unsigned long); //控制
int (*read_time)(struct device *, struct rtc_time *); //读时间
int (*set_time)(struct device *, struct rtc_time *); //设置时间
int (*read_alarm)(struct device *, struct rtc_wkalrm *); //读闹钟
int (*set_alarm)(struct device *, struct rtc_wkalrm *); //设闹钟
int (*proc)(struct device *, struct seq_file *); //proc接口
int (*set_mmss)(struct device *, unsigned long secs); //设置时间mmss
int (*irq_set_state)(struct device *, int enabled); //设置中断状态
int (*irq_set_freq)(struct device *, int freq); //设置中断频率
int (*read_callback)(struct device *, int data); //读回调函数
int (*alarm_irq_enable)(struct device *, unsigned int enabled); //闹钟中断使能
int (*update_irq_enable)(struct device *, unsigned int enabled); //更新中断使能
};
这里有两种设置时间的方法set_time和set_mmss,看它们参数可以区别出set_time使用rtc时间来设置,
set_mmss是根据秒数来设置(“Gregorian”时间)
二.rtc架构
1.rtc设备初始化函数
void __init rtc_dev_init(void) //入口函数
{
int err;
err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc"); //动态分配rtc设备号 RTC_DEV_MAX=16个
if (err < 0)
printk(KERN_ERR "%s: failed to allocate char dev region\n",__FILE__);
}
2.rtc设备的注册
rtc注册由具体设备驱动调用,同时设备驱动必须提供rtc_class_ops操作函数集
struct rtc_device *rtc_device_register(const char *name, struct device *dev,const struct rtc_class_ops *ops,struct module *owner)
{
struct rtc_device *rtc; //rtc设备
int id, err;
if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) { //idr机制预分配
err = -ENOMEM;
goto exit;
}
mutex_lock(&idr_lock);
err = idr_get_new(&rtc_idr, NULL, &id); //通过idr机制获取id号
mutex_unlock(&idr_lock);
if (err < 0)
goto exit;
id = id & MAX_ID_MASK; //id掩码过滤
rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL); //分配rtc设备
if (rtc == NULL) {
err = -ENOMEM;
goto exit_idr;
}
rtc->id = id; //次设备号
rtc->ops = ops; //rtc类操作函数集
rtc->owner = owner; //所有者
rtc->max_user_freq = 64; //最大用户频率
rtc->dev.parent = dev; //设备父设备
rtc->dev.class = rtc_class; //2.1 设备类
rtc->dev.release = rtc_device_release; //设备释放方法
mutex_init(&rtc->ops_lock);
spin_lock_init(&rtc->irq_lock);
spin_lock_init(&rtc->irq_task_lock);
init_waitqueue_head(&rtc->irq_queue);
strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); //设置rtc设备名
dev_set_name(&rtc->dev, "rtc%d", id); //设置设备名
rtc_dev_prepare(rtc); //2.2 rtc设备准备
err = device_register(&rtc->dev); //注册设备文件
if (err) {
put_device(&rtc->dev);
goto exit_kfree;
}
rtc_dev_add_device(rtc); //2.3 rtc添加设备
rtc_sysfs_add_device(rtc); //sysfs添加设备文件
rtc_proc_add_device(rtc); //procfs添加设备文件
dev_info(dev, "rtc core: registered %s as %s\n",rtc->name, dev_name(&rtc->dev));
return rtc;
exit_kfree:
kfree(rtc);
exit_idr:
mutex_lock(&idr_lock);
idr_remove(&rtc_idr, id);
mutex_unlock(&idr_lock);
exit:
dev_err(dev, "rtc core: unable to register %s, err = %d\n",name, err);
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(rtc_device_register);
2.1 设备类rtc_class
subsys_initcall(rtc_init); //rtc子系统初始化
设备类初始化
static int __init rtc_init(void)
{
rtc_class = class_create(THIS_MODULE, "rtc"); //创建设备类“/sys/class/rtc”
if (IS_ERR(rtc_class)) {
printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
return PTR_ERR(rtc_class);
}
rtc_class->suspend = rtc_suspend; //挂起
rtc_class->resume = rtc_resume; //唤醒
rtc_dev_init(); //这里发现 rtc设备初始化函数是在这里调用
rtc_sysfs_init(rtc_class); //sysfs接口
return 0;
}
rtc子系统初始化:rtc类初始化->rtc设备初始化->注册rtc设备
2.2 rtc设备准备
void rtc_dev_prepare(struct rtc_device *rtc)
{
if (!rtc_devt) //主设备号是否分配
return;
if (rtc->id >= RTC_DEV_MAX) { //判断次设备号是否>16,最多支持16个RTC
pr_debug("%s: too many RTC devices\n", rtc->name);
return;
}
rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); //设置rtc设备号
cdev_init(&rtc->char_dev, &rtc_dev_fops); //初始化字符设备 捆绑了字符设备操作函数集
rtc->char_dev.owner = rtc->owner; //模块所有者
}
2.3 rtc添加设备
void rtc_dev_add_device(struct rtc_device *rtc)
{
if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1)) //添加字符设备
printk(KERN_WARNING "%s: failed to add char device %d:%d\n",rtc->name, MAJOR(rtc_devt), rtc->id);
else
pr_debug("%s: dev (%d:%d)\n", rtc->name,MAJOR(rtc_devt), rtc->id);
}
字符设备相关的初始化总结:
"1"分配设备号,"2.2"初始化字符设备(捆绑操作函数集),“2.3”添加字符设备
“2.1”初始化设备类 "2"注册设备文件
rtc字符设备操作函数集rtc_dev_fops是系统提供的,每次操作/dev/rtcXXX就会调用其操作函数集的方法
三.rtc设备接口
1.rtc字符设备操作函数集
static const struct file_operations rtc_dev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = rtc_dev_read, //读方法
.poll = rtc_dev_poll, //轮询
.unlocked_ioctl = rtc_dev_ioctl, //控制
.open = rtc_dev_open, //打开
.release = rtc_dev_release, //释放
.fasync = rtc_dev_fasync, //异步通知
};
2.open方法
static int rtc_dev_open(struct inode *inode, struct file *file)
{
int err;
struct rtc_device *rtc = container_of(inode->i_cdev,struct rtc_device, char_dev); //获取对应的rtc设备
const struct rtc_class_ops *ops = rtc->ops; //获取对应的rtc设备类操作函数集
if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags)) //测试是否忙,不忙则设置忙标志
return -EBUSY;
file->private_data = rtc; //将rtc设备作为文件的私有数据
err = ops->open ? ops->open(rtc->dev.parent) : 0; //存在open方法则调用其open方法
if (err == 0) {
spin_lock_irq(&rtc->irq_lock);
rtc->irq_data = 0; //中断数据清0
spin_unlock_irq(&rtc->irq_lock);
return 0;
}
clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); //清除忙标志
return err;
}
涉及两个操作函数集
a.rtc设备类操作函数集 rtc_class_ops --- 具体设备驱动提供
b.rtc字符设备操作函数集 rtc_dev_fops --- rtc子系统提供
3.ioctl方法
3.1控制命令定义
#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on 使能RTC闹钟中断*/
#define RTC_AIE_OFF _IO('p', 0x02) /* ... off 禁用RTC闹钟中断*/
#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on 使能更新RTC中断*/
#define RTC_UIE_OFF _IO('p', 0x04) /* ... off 禁能更新RTC中断*/
#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on 使能RTC周期中断*/
#define RTC_PIE_OFF _IO('p', 0x06) /* ... off 禁能RTC周期中断*/
#define RTC_ALM_SET _IOW('p', 0x07, struct rtc_time) /* Set alarm time 设置闹钟时间*/
#define RTC_ALM_READ _IOR('p', 0x08, struct rtc_time) /* Read alarm time 读取闹钟时间*/
#define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time) /* Read RTC time 读取时间与日期*/
#define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time) /* Set RTC time 设置时间与日期*/
#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate 读取中断频率*/
#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate 设置中断频率*/
#define RTC_WKALM_SET _IOW('p', 0x0f, struct rtc_wkalrm) /* Set wakeup alarm 设置唤醒闹钟*/
#define RTC_WKALM_RD _IOR('p', 0x10, struct rtc_wkalrm) /* Get wakeup alarm 获取唤醒闹钟*/
命令带的参数结构体:
3.1.1 rtc时间 rtc_time
struct rtc_time { //rtc时间结构体
int tm_sec; //秒
int tm_min; //分
int tm_hour; //时
int tm_mday; //日
int tm_mon; //月
int tm_year; //年数(xxx-1900)
int tm_wday; //星期几
int tm_yday; //一年的第几天
int tm_isdst; //夏令时
};
3.1.2 rtc闹钟 rtc_wkalrm
struct rtc_wkalrm { //rtc闹钟结构体
unsigned char enabled; /* 0 = alarm disabled, 1 = alarm enabled 闹钟使能开关*/
unsigned char pending; /* 0 = alarm not pending, 1 = alarm pending 闹钟挂起*/
struct rtc_time time; /* time the alarm is set to 闹钟时间*/
};
3.2 rtc设备控制
static long rtc_dev_ioctl(struct file *file,unsigned int cmd, unsigned long arg)
{
int err = 0;
struct rtc_device *rtc &#