Linux下如何编写RTC驱动
/drivers/rtc/rtc-test.c下有一个rtc驱动的框架例程。
填写 rtc_class_ops
编写RTC内核驱动的主要步骤就是填写 rtc_class_ops。
这个结构体中使用的struct device参数就是rtc_device_register()使用的那个dev,它代表总线上的物理设备。这个
struct device的driver_data数据一般保存struct device的状态,包括指向rtc_device的指针。
驱动开发者至少应该提供read_time/set_time这两个接口,其他函数都是可选的。
141 struct rtc_class_ops {
142 int (*open)(struct device *); //打开设备时的回调函数,这个函数应该初始化硬件并申请资源
143 void (*release)(struct device *); //这个函数是设备关闭时被调用的,应该注销申请的资源。
144 int (*ioctl)(struct device *, unsigned int, unsigned long); //ioctl函数,对于想让RTC自己实现的命令应返回ENOIOCTLCMD
145 int (*read_time)(struct device *, struct rtc_time *); //读取时间
146 int (*set_time)(struct device *, struct rtc_time *); //设置时间
147 int (*read_alarm)(struct device *, struct rtc_wkalrm *); //读取下一次定时中断的时间
148 int (*set_alarm)(struct device *, struct rtc_wkalrm *); //设置下一次定时中断的时间
149 int (*proc)(struct device *, struct seq_file *); //procfs接口,该函数决定你在终端中cat /proc/driver/rtc时输出相关的信息
150 int (*set_mmss)(struct device *, unsigned long secs); // 将传入的参数secs转换为struct rtc_time然后调用set_time函数。程序员可以不实现这个函数,但前提是定义好了read_time/set_time,因为RTC框架需要用这两个函数来实现这个功能。
151 int (*irq_set_state)(struct device *, int enabled); //周期采样中断的开关,根据enabled的值来设置
152 int (*irq_set_freq)(struct device *, int freq); //设置周期中断的频率
153 int (*read_callback)(struct device *, int data); //用户空间获得数据后会传入读取的数据,并用这个函数返回的数据更新数据。
154 int (*alarm_irq_enable)(struct device *, unsigned int enabled); //alarm中断使能开关,根据enabled的值来设置
155 int (*update_irq_enable)(struct device *, unsigned int enabled); //更新中断使能开关,根据enabled的值来设置
156 };
142 int (*open)(struct device *); //打开设备时的回调函数,这个函数应该初始化硬件并申请资源
143 void (*release)(struct device *); //这个函数是设备关闭时被调用的,应该注销申请的资源。
144 int (*ioctl)(struct device *, unsigned int, unsigned long); //ioctl函数,对于想让RTC自己实现的命令应返回ENOIOCTLCMD
145 int (*read_time)(struct device *, struct rtc_time *); //读取时间
146 int (*set_time)(struct device *, struct rtc_time *); //设置时间
147 int (*read_alarm)(struct device *, struct rtc_wkalrm *); //读取下一次定时中断的时间
148 int (*set_alarm)(struct device *, struct rtc_wkalrm *); //设置下一次定时中断的时间
149 int (*proc)(struct device *, struct seq_file *); //procfs接口,该函数决定你在终端中cat /proc/driver/rtc时输出相关的信息
150 int (*set_mmss)(struct device *, unsigned long secs); // 将传入的参数secs转换为struct rtc_time然后调用set_time函数。程序员可以不实现这个函数,但前提是定义好了read_time/set_time,因为RTC框架需要用这两个函数来实现这个功能。
151 int (*irq_set_state)(struct device *, int enabled); //周期采样中断的开关,根据enabled的值来设置
152 int (*irq_set_freq)(struct device *, int freq); //设置周期中断的频率
153 int (*read_callback)(struct device *, int data); //用户空间获得数据后会传入读取的数据,并用这个函数返回的数据更新数据。
154 int (*alarm_irq_enable)(struct device *, unsigned int enabled); //alarm中断使能开关,根据enabled的值来设置
155 int (*update_irq_enable)(struct device *, unsigned int enabled); //更新中断使能开关,根据enabled的值来设置
156 };
1.免定义的ioctl命令
这里的ioctl函数并不一定要实现所有的命令,对于一些命令如果rtc_class_ops的ioctl返回ENOIOCTLCMD的话,内核的RTC子系统会
实现这些命令的方法。不需要自己实现的命令有:
* RTC_RD_TIME, RTC_SET_TIME read_time/set_time
* RTC_ALM_SET, RTC_ALM_READ, RTC_WKALM_SET, RTC_WKALM_RD 调用set_alarm/read_alarm
* RTC_IRQP_SET, RTC_IRQP_READ 调用 irq_set_freq来实现。如果不支持修改中断频率,就不要定义这个函数。
* RTC_PIE_ON, RTC_PIE_OFF 通过irq_set_state来实现。
RTC子系统实现这些命令的方式是调用你编写的函数,如果根本不提供这些函数的话,也根本不能实现这些命令。
2.read_callback
每次有数据可读取,read_callback便会被调用。
如果定义了read_callback,用户空间读取到的实际是read_callback返回的值。
文件/drivers/rtc/rtc-dev.c的rtc_dev_read函数中可了解read_callback与irq_data之间的关系
static ssize_t
rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
。。。。。。。。。。
//这里睡眠并等待读取数据
。。。。。。。。。。
//这里睡眠并等待读取数据
。。。。。。。。。。
if (ret == 0) {//如果读取到有效数据
/* Check for any data updates */
if (rtc->ops->read_callback)
data = rtc->ops->read_callback(rtc->dev.parent, data);//调用read_callback并用它返回的值更新数据
if (sizeof(int) != sizeof(long) &&
count == sizeof(unsigned int))
ret = put_user(data, (unsigned int __user *)buf) ?:
sizeof(unsigned int);
else
ret = put_user(data, (unsigned long __user *)buf) ?:
sizeof(unsigned long);
}
return ret;
}
/* Check for any data updates */
if (rtc->ops->read_callback)
data = rtc->ops->read_callback(rtc->dev.parent, data);//调用read_callback并用它返回的值更新数据
if (sizeof(int) != sizeof(long) &&
count == sizeof(unsigned int))
ret = put_user(data, (unsigned int __user *)buf) ?:
sizeof(unsigned int);
else
ret = put_user(data, (unsigned long __user *)buf) ?:
sizeof(unsigned long);
}
return ret;
}
3.中断处理函数报告事件类型。
RTC支持各种中断,中断处理函数中应该向系统中报告中断的事件类型。
一个RTC中断处理函数的例子如下:
static irqreturn_t sep0611_rtc_isr(int irq, void *id)
{
unsigned int int_stat;
struct rtc_device *rdev = id;
void __iomem *base = sep0611_rtc_base;
int_stat = readl(base + SEP0611_RTC_INT_STS);
writel(int_stat, base + SEP0611_RTC_INT_STS);
if (int_stat & ALARM_FLAG) {
rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF);
}
if (int_stat & SAMP_FLAG) {
/*reload the samp_count every time after a samp_int triggers*/
writel(SAMP_COUNT << 16, base + SEP0611_RTC_SAMP);
rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF);
}
if (int_stat & SEC_FLAG) {
rtc_update_irq(rdev, 1, RTC_UF | RTC_IRQF);
}
return IRQ_HANDLED;
}
{
unsigned int int_stat;
struct rtc_device *rdev = id;
void __iomem *base = sep0611_rtc_base;
int_stat = readl(base + SEP0611_RTC_INT_STS);
writel(int_stat, base + SEP0611_RTC_INT_STS);
if (int_stat & ALARM_FLAG) {
rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF);
}
if (int_stat & SAMP_FLAG) {
/*reload the samp_count every time after a samp_int triggers*/
writel(SAMP_COUNT << 16, base + SEP0611_RTC_SAMP);
rtc_update_irq(rdev, 1, RTC_PF | RTC_IRQF);
}
if (int_stat & SEC_FLAG) {
rtc_update_irq(rdev, 1, RTC_UF | RTC_IRQF);
}
return IRQ_HANDLED;
}
相关宏的定义如下:
#define RTC_IRQF 0x80 /* any of the following is active */
#define RTC_PF 0x40
#define RTC_AF 0x20
#define RTC_UF 0x10
#define RTC_PF 0x40
#define RTC_AF 0x20
#define RTC_UF 0x10
rtc_update_irq的原型是:
void rtc_update_irq(struct rtc_device *rtc,
unsigned long num, unsigned long events)
{
spin_lock(&rtc->irq_lock);
rtc->irq_data = (rtc->irq_data + (num << 8)) | events;
spin_unlock(&rtc->irq_lock);
spin_lock(&rtc->irq_task_lock);
if (rtc->irq_task)
rtc->irq_task->func(rtc->irq_task->private_data);
spin_unlock(&rtc->irq_task_lock);
wake_up_interruptible(&rtc->irq_queue);
kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
}
unsigned long num, unsigned long events)
{
spin_lock(&rtc->irq_lock);
rtc->irq_data = (rtc->irq_data + (num << 8)) | events;
spin_unlock(&rtc->irq_lock);
spin_lock(&rtc->irq_task_lock);
if (rtc->irq_task)
rtc->irq_task->func(rtc->irq_task->private_data);
spin_unlock(&rtc->irq_task_lock);
wake_up_interruptible(&rtc->irq_queue);
kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
}
其中num是上次报告以来中断发生的次数,events是事件类型掩码。
相关推荐
kanpiaoxue 2013-06-19
RexLeee 2019-12-23
fouweng 2011-08-27
Tinazhou 2016-11-22
molong0 2017-07-13
ECSHOP专属建设 2016-11-25
ruizhenggang 2011-10-11
BlogForUS 2018-01-22
cxj 2019-10-08
lilygg 2019-10-04
啦啦啦啦啦 2019-09-29
二哈 2012-02-12
小微分享驿站 2011-12-28
ArchitetYang 2011-12-07