深入解析linux下rtc架构

一.描述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 &#
  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值