RTC源代码分析

花了一个下午时间,把rtc代码的架构弄懂了,如下图所示:

 

下面附上各个包含详细注释的C文件源代码:

 

class.c源代码:

  1 /*
  2  * RTC subsystem, base class
  3  *
  4  * Copyright (C) 2005 Tower Technologies
  5  * Author: Alessandro Zummo <a.zummo@towertech.it>
  6  *
  7  * class skeleton from drivers/hwmon/hwmon.c
  8  *
  9  * This program is free software; you can redistribute it and/or modify
 10  * it under the terms of the GNU General Public License version 2 as
 11  * published by the Free Software Foundation.
 12 本c文件工作总结:
 13 1.在init函数中:
 14     (1):创建sysfs文件系统的/sys/class/rtc目录,并且初始化rtc类的相关成员
 15         作用:向用户空间提供设备的信息,驱动程序不需要直接处理类
 16     (2):动态分配rtc字符设备的设备号
 17     (3):初始化rtc的/sys/class/rtc目录中的属性文件
 18 2.在exit函数中:
 19     (1):注销rtc设备号
 20     (2):注销sysfs文件系统的/sys/class/rtc目录。
 21 3.在rtc_device_register中
 22     (1):申请一个idr整数ID管理机制结构体,并且初始化相关成员
 23     (2):将设备dev关联sysfs下的rtc类
 24     (3):初始化rtc结构体的信号量
 25     (4):初始化rtc结构体中的中断
 26     (5):设置rtc的名字
 27     (6):初始化rtc字符设备的设备号,然后注册rtc设备,自动创建/dev/rtc(n)设备节点文件
 28     (7):注册字符设备
 29     (8):在/sys/rtc/目录下创建一个闹钟属性文件
 30     (9):创建/proc/driver/rtc目录
 31 4.在rtc_device_unregister中
 32     (1):删除sysfs中的rtc设备,即删除/sys/class/rtc目录
 33     (2):删除dev下的/dev/rtc(n)设备节点文件
 34     (3):删除虚拟文件系统接口,即删除/proc/driver/rtc目录
 35     (4):卸载字符设备
 36     (5):清空rtc的操作函数指针rtc->ops
 37     (6):释放rtc的device结构体
 38 5.在rtc_device_release函数中
 39     (1):卸载idr数字管理机制结构体
 40     (2):释放rtc结构体的内存
 41 */
 42 
 43 #include <linux/module.h>
 44 #include <linux/rtc.h>
 45 #include <linux/kdev_t.h>
 46 #include <linux/idr.h>
 47 
 48 #include "rtc-core.h"
 49 static DEFINE_MUTEX
 50 
 51 static DEFINE_IDR(rtc_idr);   //定义整数ID管理机制idr结构体
 52 (idr_lock);
 53 struct class *rtc_class;      //定义sysfs的类结构体
 54 
 55 static void rtc_device_release(struct device *dev)
 56 {
 57     struct rtc_device *rtc = to_rtc_device(dev);
 58     mutex_lock(&idr_lock);
 59     idr_remove(&rtc_idr, rtc->id);     //卸载idr数字管理机制结构体
 60     mutex_unlock(&idr_lock);
 61     kfree(rtc);                        //释放rtc结构体的内存
 62 }
 63 
 64 #if defined(CONFIG_PM) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
 65 
 66 /*
 67  * On suspend(), measure the delta between one RTC and the
 68  * system's wall clock; restore it on resume().
 69  */
 70 
 71 static struct timespec    delta;
 72 static time_t        oldtime;
 73 
 74 static int rtc_suspend(struct device *dev, pm_message_t mesg)
 75 {
 76     struct rtc_device    *rtc = to_rtc_device(dev);
 77     struct rtc_time        tm;
 78     struct timespec        ts = current_kernel_time();
 79 
 80     if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
 81         return 0;
 82 
 83     rtc_read_time(rtc, &tm);
 84     rtc_tm_to_time(&tm, &oldtime);
 85 
 86     /* RTC precision is 1 second; adjust delta for avg 1/2 sec err */
 87     set_normalized_timespec(&delta,
 88                 ts.tv_sec - oldtime,
 89                 ts.tv_nsec - (NSEC_PER_SEC >> 1));
 90 
 91     return 0;
 92 }
 93 
 94 static int rtc_resume(struct device *dev)
 95 {
 96     struct rtc_device    *rtc = to_rtc_device(dev);
 97     struct rtc_time        tm;
 98     time_t            newtime;
 99     struct timespec        time;
100 
101     if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
102         return 0;
103 
104     rtc_read_time(rtc, &tm);
105     if (rtc_valid_tm(&tm) != 0) {
106         pr_debug("%s:  bogus resume time\n", dev_name(&rtc->dev));
107         return 0;
108     }
109     rtc_tm_to_time(&tm, &newtime);
110     if (newtime <= oldtime) {
111         if (newtime < oldtime)
112             pr_debug("%s:  time travel!\n", dev_name(&rtc->dev));
113         return 0;
114     }
115 
116     /* restore wall clock using delta against this RTC;
117      * adjust again for avg 1/2 second RTC sampling error
118      */
119     set_normalized_timespec(&time,
120                 newtime + delta.tv_sec,
121                 (NSEC_PER_SEC >> 1) + delta.tv_nsec);
122     do_settimeofday(&time);
123 
124     return 0;
125 }
126 
127 #else
128 #define rtc_suspend    NULL
129 #define rtc_resume    NULL
130 #endif
131 
132 
133 /**
134  * rtc_device_register - register w/ RTC class
135  * @dev: the device to register
136  *
137  * rtc_device_unregister() must be called when the class device is no
138  * longer needed.
139  *
140  * Returns the pointer to the new struct class device.
141  */
142 struct rtc_device *rtc_device_register(const char *name, struct device *dev,
143                     const struct rtc_class_ops *ops,
144                     struct module *owner)
145 {
146     struct rtc_device *rtc;
147     int id, err;
148     //整数ID管理机制
149     if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {   //检测IDR是否能正常获取
150         err = -ENOMEM;
151         goto exit;
152     }
153 
154 
155     mutex_lock(&idr_lock);                   //原子操作,上锁,防止被打断
156     err = idr_get_new(&rtc_idr, NULL, &id);  //获取一个idr结构,并与id相关联
157     mutex_unlock(&idr_lock);                 //解锁
158 
159     if (err < 0)
160         goto exit;
161 
162     id = id & MAX_ID_MASK;          //将32为id的无效高位清零
163 
164     rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);  //分配一个rtc_device结构体
165     if (rtc == NULL) {
166         err = -ENOMEM;
167         goto exit_idr;
168     }
169 
170     rtc->id = id;            //整数ID管理机制
171     rtc->ops = ops;          //关联定义的操作函数结构体  open,release,ioctl等函数
172     rtc->owner = owner;      //所属模块的相关信息
173     rtc->max_user_freq = 64; //最大使用数量 64
174     rtc->dev.parent = dev;   //父设备
175     rtc->dev.class = rtc_class;  //包含的sysfs下面的类
176     rtc->dev.release = rtc_device_release;  //释放函数
177 
178     mutex_init(&rtc->ops_lock);       //初始化信号量
179     spin_lock_init(&rtc->irq_lock);   
180     spin_lock_init(&rtc->irq_task_lock);
181     init_waitqueue_head(&rtc->irq_queue);   //定义rtc中断
182 
183     strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);  //设置rtc的名字
184     dev_set_name(&rtc->dev, "rtc%d", id);   
185 
186     rtc_dev_prepare(rtc);              //初始化rtc字符设备的设备号  
187 
188     err = device_register(&rtc->dev);  //注册rtc设备,这样rtc会自动创建设备文件rtc(n)
189     if (err)
190         goto exit_kfree;
191 
192     rtc_dev_add_device(rtc);    //注册字符设备
193     rtc_sysfs_add_device(rtc);  //为设备添加一个闹钟属性,在/sys/rtc下面创建闹钟属性文件
194     rtc_proc_add_device(rtc);   //穿件proc文件结构体  在/proc目录下创建 driver/rtc
195 
196     dev_info(dev, "rtc core: registered %s as %s\n",
197             rtc->name, dev_name(&rtc->dev));  //打印信息
198 
199     return rtc;
200 
201 exit_kfree:
202     kfree(rtc);
203 
204 exit_idr:
205     mutex_lock(&idr_lock);
206     idr_remove(&rtc_idr, id);
207     mutex_unlock(&idr_lock);
208 
209 exit:
210     dev_err(dev, "rtc core: unable to register %s, err = %d\n",
211             name, err);
212     return ERR_PTR(err);
213 }
214 EXPORT_SYMBOL_GPL(rtc_device_register);
215 
216 
217 /**
218  * rtc_device_unregister - removes the previously registered RTC class device
219  *
220  * @rtc: the RTC class device to destroy
221  */
222 void rtc_device_unregister(struct rtc_device *rtc)
223 {
224     if (get_device(&rtc->dev) != NULL) {
225         mutex_lock(&rtc->ops_lock);     //上锁
226         /* remove innards of this RTC, then disable it, before
227          * letting any rtc_class_open() users access it again
228          */
229         rtc_sysfs_del_device(rtc);     //删除sysfs下面的rtc设备
230         rtc_dev_del_device(rtc);       //删除dev下的rtc
231         rtc_proc_del_device(rtc);      //删除虚拟文件系统接口
232         device_unregister(&rtc->dev);  //卸载字符设备
233         rtc->ops = NULL;               //将rtc的操作函数指针清空
234         mutex_unlock(&rtc->ops_lock);  //解锁
235         put_device(&rtc->dev);         //释放rtc的device结构体
236     }
237 }
238 EXPORT_SYMBOL_GPL(rtc_device_unregister);
239 
240 static int __init rtc_init(void)
241 {
242     rtc_class = class_create(THIS_MODULE, "rtc");//在/sys/class下面创建类目录,类名为rtc
243     if (IS_ERR(rtc_class)) {
244         printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
245         return PTR_ERR(rtc_class);
246     }
247     //类的作用就是向用户空间提供设备的信息,驱动程序不需要直接处理类
248     rtc_class->suspend = rtc_suspend;   //初始化类结构体的相关成员
249     rtc_class->resume = rtc_resume;     //动态分配rtc的设备号
250     rtc_dev_init();                     //动态分配
251     rtc_sysfs_init(rtc_class);          //初始化rtc的属性文件
252     return 0;
253 }
254 
255 static void __exit rtc_exit(void)
256 {
257     rtc_dev_exit();                     //注销rtc设备号
258     class_destroy(rtc_class);           //注销/sys/class下的类目录
259 }
260 
261 subsys_initcall(rtc_init);
262 module_exit(rtc_exit);
263 
264 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
265 MODULE_DESCRIPTION("RTC class support");
266 MODULE_LICENSE("GPL");
class.c

 

rtc-dev.c源代码:

  1 /*
  2  * RTC subsystem, dev interface
  3  *
  4  * Copyright (C) 2005 Tower Technologies
  5  * Author: Alessandro Zummo <a.zummo@towertech.it>
  6  *
  7  * based on arch/arm/common/rtctime.c
  8  *
  9  * This program is free software; you can redistribute it and/or modify
 10  * it under the terms of the GNU General Public License version 2 as
 11  * published by the Free Software Foundation.
 12 
 13 本程序大致内容
 14 1.在init函数中动态的申请字符设备的设备号
 15 2.实现struct file_operations rtc_dev_fops 结构体及其默认函数
 16 3.在exit中注销字符设备设备号
 17 */
 18 
 19 #include <linux/module.h>
 20 #include <linux/rtc.h>
 21 #include "rtc-core.h"
 22 
 23 static dev_t rtc_devt;
 24 
 25 #define RTC_DEV_MAX 16 /* 16 RTCs should be enough for everyone... */
 26 
 27 static int rtc_dev_open(struct inode *inode, struct file *file)
 28 {
 29     int err;
 30     struct rtc_device *rtc = container_of(inode->i_cdev,
 31                     struct rtc_device, char_dev);
 32     const struct rtc_class_ops *ops = rtc->ops;
 33 
 34     if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags))
 35         return -EBUSY;
 36 
 37     file->private_data = rtc;
 38 
 39     err = ops->open ? ops->open(rtc->dev.parent) : 0;
 40     if (err == 0) {
 41         spin_lock_irq(&rtc->irq_lock);
 42         rtc->irq_data = 0;
 43         spin_unlock_irq(&rtc->irq_lock);
 44 
 45         return 0;
 46     }
 47 
 48     /* something has gone wrong */
 49     clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
 50     return err;
 51 }
 52 
 53 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
 54 /*
 55  * Routine to poll RTC seconds field for change as often as possible,
 56  * after first RTC_UIE use timer to reduce polling
 57  */
 58 static void rtc_uie_task(struct work_struct *work)
 59 {
 60     struct rtc_device *rtc =
 61         container_of(work, struct rtc_device, uie_task);
 62     struct rtc_time tm;
 63     int num = 0;
 64     int err;
 65 
 66     err = rtc_read_time(rtc, &tm);
 67 
 68     spin_lock_irq(&rtc->irq_lock);
 69     if (rtc->stop_uie_polling || err) {
 70         rtc->uie_task_active = 0;
 71     } else if (rtc->oldsecs != tm.tm_sec) {
 72         num = (tm.tm_sec + 60 - rtc->oldsecs) % 60;
 73         rtc->oldsecs = tm.tm_sec;
 74         rtc->uie_timer.expires = jiffies + HZ - (HZ/10);
 75         rtc->uie_timer_active = 1;
 76         rtc->uie_task_active = 0;
 77         add_timer(&rtc->uie_timer);
 78     } else if (schedule_work(&rtc->uie_task) == 0) {
 79         rtc->uie_task_active = 0;
 80     }
 81     spin_unlock_irq(&rtc->irq_lock);
 82     if (num)
 83         rtc_update_irq(rtc, num, RTC_UF | RTC_IRQF);
 84 }
 85 static void rtc_uie_timer(unsigned long data)
 86 {
 87     struct rtc_device *rtc = (struct rtc_device *)data;
 88     unsigned long flags;
 89 
 90     spin_lock_irqsave(&rtc->irq_lock, flags);
 91     rtc->uie_timer_active = 0;
 92     rtc->uie_task_active = 1;
 93     if ((schedule_work(&rtc->uie_task) == 0))
 94         rtc->uie_task_active = 0;
 95     spin_unlock_irqrestore(&rtc->irq_lock, flags);
 96 }
 97 
 98 static int clear_uie(struct rtc_device *rtc)
 99 {
100     spin_lock_irq(&rtc->irq_lock);
101     if (rtc->uie_irq_active) {
102         rtc->stop_uie_polling = 1;
103         if (rtc->uie_timer_active) {
104             spin_unlock_irq(&rtc->irq_lock);
105             del_timer_sync(&rtc->uie_timer);
106             spin_lock_irq(&rtc->irq_lock);
107             rtc->uie_timer_active = 0;
108         }
109         if (rtc->uie_task_active) {
110             spin_unlock_irq(&rtc->irq_lock);
111             flush_scheduled_work();
112             spin_lock_irq(&rtc->irq_lock);
113         }
114         rtc->uie_irq_active = 0;
115     }
116     spin_unlock_irq(&rtc->irq_lock);
117     return 0;
118 }
119 
120 static int set_uie(struct rtc_device *rtc)
121 {
122     struct rtc_time tm;
123     int err;
124 
125     err = rtc_read_time(rtc, &tm);
126     if (err)
127         return err;
128     spin_lock_irq(&rtc->irq_lock);
129     if (!rtc->uie_irq_active) {
130         rtc->uie_irq_active = 1;
131         rtc->stop_uie_polling = 0;
132         rtc->oldsecs = tm.tm_sec;
133         rtc->uie_task_active = 1;
134         if (schedule_work(&rtc->uie_task) == 0)
135             rtc->uie_task_active = 0;
136     }
137     rtc->irq_data = 0;
138     spin_unlock_irq(&rtc->irq_lock);
139     return 0;
140 }
141 
142 int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled)
143 {
144     if (enabled)
145         return set_uie(rtc);
146     else
147         return clear_uie(rtc);
148 }
149 EXPORT_SYMBOL(rtc_dev_update_irq_enable_emul);
150 
151 #endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */
152 
153 static ssize_t
154 rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
155 {
156     struct rtc_device *rtc = file->private_data;
157 
158     DECLARE_WAITQUEUE(wait, current);    //声明一个等待队列入口
159     unsigned long data;
160     ssize_t ret;
161 
162     if (count != sizeof(unsigned int) && count < sizeof(unsigned long))
163         return -EINVAL;
164 
165     add_wait_queue(&rtc->irq_queue, &wait);//将这个等待队列的入口加入到rtc的irq等待队列中
166     do {
167         __set_current_state(TASK_INTERRUPTIBLE);//把当前进程的状态修改为TASK_INTERRUPTIBLE
168 
169         spin_lock_irq(&rtc->irq_lock); //保护代码段不被抢占(禁止 IRQ 同时也就隐式地禁止了抢占),既禁止本地中断,又禁止内核抢占。
170         data = rtc->irq_data;
171         rtc->irq_data = 0;
172         spin_unlock_irq(&rtc->irq_lock);
173 
174         if (data != 0) { //如果数据不是零的话说明发生过一次中断
175             ret = 0;
176             break;
177         }
178         if (file->f_flags & O_NONBLOCK) { //如果打开方式为不阻塞的话,直接返回
179             ret = -EAGAIN;
180             break;
181         }
182         if (signal_pending(current)) {  //检查当前进程是否有信号处理,返回不为0表示有信号需要处理。
183             ret = -ERESTARTSYS;
184             break;
185         }
186         schedule();  //如果没有发生过中断,并且也没有信号处理,则调度
187     } while (1);
188     set_current_state(TASK_RUNNING);//把当前进程的状态修改为TASK_RUNNING
189 
190     remove_wait_queue(&rtc->irq_queue, &wait); //移除等待队列
191  
192     if (ret == 0) {  //如果发生过中断
193         /* Check for any data updates */
194         if (rtc->ops->read_callback)
195             data = rtc->ops->read_callback(rtc->dev.parent,
196                                data);
197 
198         if (sizeof(int) != sizeof(long) &&
199             count == sizeof(unsigned int))
200             ret = put_user(data, (unsigned int __user *)buf) ?:
201                 sizeof(unsigned int);
202         else
203             ret = put_user(data, (unsigned long __user *)buf) ?:
204                 sizeof(unsigned long);
205     }
206     return ret;
207 }
208 
209 static unsigned int rtc_dev_poll(struct file *file, poll_table *wait)
210 {
211     struct rtc_device *rtc = file->private_data;
212     unsigned long data;
213 
214     poll_wait(file, &rtc->irq_queue, wait);  //监控文件,加入等待队列
215 
216     data = rtc->irq_data;
217 
218     return (data != 0) ? (POLLIN | POLLRDNORM) : 0;
219 }
220 
221 static long rtc_dev_ioctl(struct file *file,
222         unsigned int cmd, unsigned long arg)
223 {
224     int err = 0;
225     struct rtc_device *rtc = file->private_data;
226     const struct rtc_class_ops *ops = rtc->ops;
227     struct rtc_time tm;
228     struct rtc_wkalrm alarm;
229     void __user *uarg = (void __user *) arg;
230 
231     err = mutex_lock_interruptible(&rtc->ops_lock);
232     if (err)
233         return err;
234 
235     /* check that the calling task has appropriate permissions
236      * for certain ioctls. doing this check here is useful
237      * to avoid duplicate code in each driver.
238      */
239     switch (cmd) {
240     case RTC_EPOCH_SET:
241     case RTC_SET_TIME:
242         if (!capable(CAP_SYS_TIME))
243             err = -EACCES;
244         break;
245 
246     case RTC_IRQP_SET:
247         if (arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE))
248             err = -EACCES;
249         break;
250 
251     case RTC_PIE_ON:
252         if (rtc->irq_freq > rtc->max_user_freq &&
253                 !capable(CAP_SYS_RESOURCE))
254             err = -EACCES;
255         break;
256     }
257 
258     if (err)
259         goto done;
260 
261     /* try the driver's ioctl interface */
262     if (ops->ioctl) {
263         err = ops->ioctl(rtc->dev.parent, cmd, arg);
264         if (err != -ENOIOCTLCMD) {
265             mutex_unlock(&rtc->ops_lock);
266             return err;
267         }
268     }
269 
270     /* if the driver does not provide the ioctl interface
271      * or if that particular ioctl was not implemented
272      * (-ENOIOCTLCMD), we will try to emulate here.
273      *
274      * Drivers *SHOULD NOT* provide ioctl implementations
275      * for these requests.  Instead, provide methods to
276      * support the following code, so that the RTC's main
277      * features are accessible without using ioctls.
278      *
279      * RTC and alarm times will be in UTC, by preference,
280      * but dual-booting with MS-Windows implies RTCs must
281      * use the local wall clock time.
282      */
283 
284     switch (cmd) {
285     case RTC_ALM_READ:
286         mutex_unlock(&rtc->ops_lock);
287 
288         err = rtc_read_alarm(rtc, &alarm);
289         if (err < 0)
290             return err;
291 
292         if (copy_to_user(uarg, &alarm.time, sizeof(tm)))
293             err = -EFAULT;
294         return err;
295 
296     case RTC_ALM_SET:
297         mutex_unlock(&rtc->ops_lock);
298 
299         if (copy_from_user(&alarm.time, uarg, sizeof(tm)))
300             return -EFAULT;
301 
302         alarm.enabled = 0;
303         alarm.pending = 0;
304         alarm.time.tm_wday = -1;
305         alarm.time.tm_yday = -1;
306         alarm.time.tm_isdst = -1;
307 
308         /* RTC_ALM_SET alarms may be up to 24 hours in the future.
309          * Rather than expecting every RTC to implement "don't care"
310          * for day/month/year fields, just force the alarm to have
311          * the right values for those fields.
312          *
313          * RTC_WKALM_SET should be used instead.  Not only does it
314          * eliminate the need for a separate RTC_AIE_ON call, it
315          * doesn't have the "alarm 23:59:59 in the future" race.
316          *
317          * NOTE:  some legacy code may have used invalid fields as
318          * wildcards, exposing hardware "periodic alarm" capabilities.
319          * Not supported here.
320          */
321         {
322             unsigned long now, then;
323 
324             err = rtc_read_time(rtc, &tm);
325             if (err < 0)
326                 return err;
327             rtc_tm_to_time(&tm, &now);
328 
329             alarm.time.tm_mday = tm.tm_mday;
330             alarm.time.tm_mon = tm.tm_mon;
331             alarm.time.tm_year = tm.tm_year;
332             err  = rtc_valid_tm(&alarm.time);
333             if (err < 0)
334                 return err;
335             rtc_tm_to_time(&alarm.time, &then);
336 
337             /* alarm may need to wrap into tomorrow */
338             if (then < now) {
339                 rtc_time_to_tm(now + 24 * 60 * 60, &tm);
340                 alarm.time.tm_mday = tm.tm_mday;
341                 alarm.time.tm_mon = tm.tm_mon;
342                 alarm.time.tm_year = tm.tm_year;
343             }
344         }
345 
346         return rtc_set_alarm(rtc, &alarm);
347 
348     case RTC_RD_TIME:
349         mutex_unlock(&rtc->ops_lock);
350 
351         err = rtc_read_time(rtc, &tm);
352         if (err < 0)
353             return err;
354 
355         if (copy_to_user(uarg, &tm, sizeof(tm)))
356             err = -EFAULT;
357         return err;
358 
359     case RTC_SET_TIME:
360         mutex_unlock(&rtc->ops_lock);
361 
362         if (copy_from_user(&tm, uarg, sizeof(tm)))
363             return -EFAULT;
364 
365         return rtc_set_time(rtc, &tm);
366 
367     case RTC_PIE_ON:
368         err = rtc_irq_set_state(rtc, NULL, 1);
369         break;
370 
371     case RTC_PIE_OFF:
372         err = rtc_irq_set_state(rtc, NULL, 0);
373         break;
374 
375     case RTC_AIE_ON:
376         mutex_unlock(&rtc->ops_lock);
377         return rtc_alarm_irq_enable(rtc, 1);
378 
379     case RTC_AIE_OFF:
380         mutex_unlock(&rtc->ops_lock);
381         return rtc_alarm_irq_enable(rtc, 0);
382 
383     case RTC_UIE_ON:
384         mutex_unlock(&rtc->ops_lock);
385         return rtc_update_irq_enable(rtc, 1);
386 
387     case RTC_UIE_OFF:
388         mutex_unlock(&rtc->ops_lock);
389         return rtc_update_irq_enable(rtc, 0);
390 
391     case RTC_IRQP_SET:
392         err = rtc_irq_set_freq(rtc, NULL, arg);
393         break;
394 
395     case RTC_IRQP_READ:
396         err = put_user(rtc->irq_freq, (unsigned long __user *)uarg);
397         break;
398 
399 #if 0
400     case RTC_EPOCH_SET:
401 #ifndef rtc_epoch
402         /*
403          * There were no RTC clocks before 1900.
404          */
405         if (arg < 1900) {
406             err = -EINVAL;
407             break;
408         }
409         rtc_epoch = arg;
410         err = 0;
411 #endif
412         break;
413 
414     case RTC_EPOCH_READ:
415         err = put_user(rtc_epoch, (unsigned long __user *)uarg);
416         break;
417 #endif
418     case RTC_WKALM_SET:
419         mutex_unlock(&rtc->ops_lock);
420         if (copy_from_user(&alarm, uarg, sizeof(alarm)))
421             return -EFAULT;
422 
423         return rtc_set_alarm(rtc, &alarm);
424 
425     case RTC_WKALM_RD:
426         mutex_unlock(&rtc->ops_lock);
427         err = rtc_read_alarm(rtc, &alarm);
428         if (err < 0)
429             return err;
430 
431         if (copy_to_user(uarg, &alarm, sizeof(alarm)))
432             err = -EFAULT;
433         return err;
434 
435     default:
436         err = -ENOTTY;
437         break;
438     }
439 
440 done:
441     mutex_unlock(&rtc->ops_lock);
442     return err;
443 }
444 
445 static int rtc_dev_fasync(int fd, struct file *file, int on)
446 {
447     struct rtc_device *rtc = file->private_data;
448     return fasync_helper(fd, file, on, &rtc->async_queue);
449 }
450 
451 static int rtc_dev_release(struct inode *inode, struct file *file)
452 {
453     struct rtc_device *rtc = file->private_data;
454 
455     /* We shut down the repeating IRQs that userspace enabled,
456      * since nothing is listening to them.
457      *  - Update (UIE) ... currently only managed through ioctls
458      *  - Periodic (PIE) ... also used through rtc_*() interface calls
459      *
460      * Leave the alarm alone; it may be set to trigger a system wakeup
461      * later, or be used by kernel code, and is a one-shot event anyway.
462      */
463 
464     /* Keep ioctl until all drivers are converted */
465     rtc_dev_ioctl(file, RTC_UIE_OFF, 0);
466     rtc_update_irq_enable(rtc, 0);
467     rtc_irq_set_state(rtc, NULL, 0);
468 
469     if (rtc->ops->release)
470         rtc->ops->release(rtc->dev.parent);
471 
472     clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
473     return 0;
474 }
475 
476 static const struct file_operations rtc_dev_fops = {
477     .owner        = THIS_MODULE,
478     .llseek        = no_llseek,
479     .read        = rtc_dev_read,
480     .poll        = rtc_dev_poll,
481     .unlocked_ioctl    = rtc_dev_ioctl,
482     .open        = rtc_dev_open,
483     .release    = rtc_dev_release,
484     .fasync        = rtc_dev_fasync,
485 };
486 
487 /* insertion/removal hooks */
488 
489 void rtc_dev_prepare(struct rtc_device *rtc)
490 {
491     if (!rtc_devt)
492         return;
493 
494     if (rtc->id >= RTC_DEV_MAX) {
495         pr_debug("%s: too many RTC devices\n", rtc->name);
496         return;
497     }
498 
499     rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);    //获取rtc的设备号
500 
501 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
502     INIT_WORK(&rtc->uie_task, rtc_uie_task);
503     setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);
504 #endif
505 
506     cdev_init(&rtc->char_dev, &rtc_dev_fops);
507     rtc->char_dev.owner = rtc->owner;
508 }
509 
510 void rtc_dev_add_device(struct rtc_device *rtc)
511 {
512     if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1))
513         printk(KERN_WARNING "%s: failed to add char device %d:%d\n",
514             rtc->name, MAJOR(rtc_devt), rtc->id);
515     else
516         pr_debug("%s: dev (%d:%d)\n", rtc->name,
517             MAJOR(rtc_devt), rtc->id);
518 }
519 
520 void rtc_dev_del_device(struct rtc_device *rtc)
521 {
522     if (rtc->dev.devt)
523         cdev_del(&rtc->char_dev);
524 }
525 
526 void __init rtc_dev_init(void)
527 {
528     int err;
529 
530     err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");   //动态分配rtc的设备号
531     if (err < 0)
532         printk(KERN_ERR "%s: failed to allocate char dev region\n",
533             __FILE__);
534 }
535 
536 void __exit rtc_dev_exit(void)
537 {
538     if (rtc_devt)
539         unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);          //注销设备号
540 }
rtc-dev.c

 

interface.c源代码:

  1 /*
  2  * RTC subsystem, interface functions
  3  *
  4  * Copyright (C) 2005 Tower Technologies
  5  * Author: Alessandro Zummo <a.zummo@towertech.it>
  6  *
  7  * based on arch/arm/common/rtctime.c
  8  *
  9  * This program is free software; you can redistribute it and/or modify
 10  * it under the terms of the GNU General Public License version 2 as
 11  * published by the Free Software Foundation.
 12 
 13 本函数中主要就是实现 前面我们rtc-dev.c中ioctl的各种命令函数
 14 RTC_ALM_READ             rtc_read_alarm             读取闹钟时间
 15 RTC_ALM_SET              rtc_set_alarm              设置闹钟时间
 16 RTC_RD_TIME              rtc_read_time              读取时间与日期
 17 RTC_SET_TIME             rtc_set_time               设置时间与日期
 18 RTC_PIE_ON RTC_PIE_OFF   rtc_irq_set_state          开关RTC全局中断的函数
 19 RTC_AIE_ON RTC_AIE_OFF   rtc_alarm_irq_enable       使能禁止RTC闹钟中断
 20 RTC_UIE_OFF RTC_UIE_ON   rtc_update_irq_enable      使能禁止RTC更新中断
 21 RTC_IRQP_SET             rtc_irq_set_freq           设置中断的频率
 22 
 23 */
 24 
 25 #include <linux/rtc.h>
 26 #include <linux/log2.h>
 27 
 28 int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
 29 {
 30     int err;
 31 
 32     err = mutex_lock_interruptible(&rtc->ops_lock); //上锁,用了一个信号来保证在同一时刻只有一个进程可以获取时间
 33     if (err)
 34         return err;
 35 
 36     if (!rtc->ops) //如果rtc的ops结构体为空,则直接返回
 37         err = -ENODEV;
 38     else if (!rtc->ops->read_time) //如果未定义ops的read_time函数,直接返回
 39         err = -EINVAL;
 40     else {
 41         memset(tm, 0, sizeof(struct rtc_time)); //将内存清零,清空tm结构体
 42         err = rtc->ops->read_time(rtc->dev.parent, tm);//读取时间
 43     }
 44 
 45     mutex_unlock(&rtc->ops_lock);//解锁
 46     return err;
 47 }
 48 EXPORT_SYMBOL_GPL(rtc_read_time);
 49 
 50 int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
 51 {
 52     int err;
 53 
 54     err = rtc_valid_tm(tm);
 55     if (err != 0)
 56         return err;
 57 
 58     err = mutex_lock_interruptible(&rtc->ops_lock);
 59     if (err)
 60         return err;
 61 
 62     if (!rtc->ops)
 63         err = -ENODEV;
 64     else if (rtc->ops->set_time)
 65         err = rtc->ops->set_time(rtc->dev.parent, tm);
 66     else if (rtc->ops->set_mmss) {
 67         unsigned long secs;
 68         err = rtc_tm_to_time(tm, &secs);
 69         if (err == 0)
 70             err = rtc->ops->set_mmss(rtc->dev.parent, secs);
 71     } else
 72         err = -EINVAL;
 73 
 74     mutex_unlock(&rtc->ops_lock);
 75     return err;
 76 }
 77 EXPORT_SYMBOL_GPL(rtc_set_time);
 78 
 79 int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
 80 {
 81     int err;
 82 
 83     err = mutex_lock_interruptible(&rtc->ops_lock);
 84     if (err)
 85         return err;
 86 
 87     if (!rtc->ops)
 88         err = -ENODEV;
 89     else if (rtc->ops->set_mmss)
 90         err = rtc->ops->set_mmss(rtc->dev.parent, secs);
 91     else if (rtc->ops->read_time && rtc->ops->set_time) {
 92         struct rtc_time new, old;
 93 
 94         err = rtc->ops->read_time(rtc->dev.parent, &old);
 95         if (err == 0) {
 96             rtc_time_to_tm(secs, &new);
 97 
 98             /*
 99              * avoid writing when we're going to change the day of
100              * the month. We will retry in the next minute. This
101              * basically means that if the RTC must not drift
102              * by more than 1 minute in 11 minutes.
103              */
104             if (!((old.tm_hour == 23 && old.tm_min == 59) ||
105                 (new.tm_hour == 23 && new.tm_min == 59)))
106                 err = rtc->ops->set_time(rtc->dev.parent,
107                         &new);
108         }
109     }
110     else
111         err = -EINVAL;
112 
113     mutex_unlock(&rtc->ops_lock);
114 
115     return err;
116 }
117 EXPORT_SYMBOL_GPL(rtc_set_mmss);
118 
119 static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
120 {
121     int err;
122 
123     err = mutex_lock_interruptible(&rtc->ops_lock);
124     if (err)
125         return err;
126 
127     if (rtc->ops == NULL)
128         err = -ENODEV;
129     else if (!rtc->ops->read_alarm)
130         err = -EINVAL;
131     else {
132         memset(alarm, 0, sizeof(struct rtc_wkalrm));
133         err = rtc->ops->read_alarm(rtc->dev.parent, alarm);
134     }
135 
136     mutex_unlock(&rtc->ops_lock);
137     return err;
138 }
139 
140 int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
141 {
142     int err;
143     struct rtc_time before, now;
144     int first_time = 1;
145     unsigned long t_now, t_alm;
146     enum { none, day, month, year } missing = none;
147     unsigned days;
148 
149     /* The lower level RTC driver may return -1 in some fields,
150      * creating invalid alarm->time values, for reasons like:
151      *
152      *   - The hardware may not be capable of filling them in;
153      *     many alarms match only on time-of-day fields, not
154      *     day/month/year calendar data.
155      *
156      *   - Some hardware uses illegal values as "wildcard" match
157      *     values, which non-Linux firmware (like a BIOS) may try
158      *     to set up as e.g. "alarm 15 minutes after each hour".
159      *     Linux uses only oneshot alarms.
160      *
161      * When we see that here, we deal with it by using values from
162      * a current RTC timestamp for any missing (-1) values.  The
163      * RTC driver prevents "periodic alarm" modes.
164      *
165      * But this can be racey, because some fields of the RTC timestamp
166      * may have wrapped in the interval since we read the RTC alarm,
167      * which would lead to us inserting inconsistent values in place
168      * of the -1 fields.
169      *
170      * Reading the alarm and timestamp in the reverse sequence
171      * would have the same race condition, and not solve the issue.
172      *
173      * So, we must first read the RTC timestamp,
174      * then read the RTC alarm value,
175      * and then read a second RTC timestamp.
176      *
177      * If any fields of the second timestamp have changed
178      * when compared with the first timestamp, then we know
179      * our timestamp may be inconsistent with that used by
180      * the low-level rtc_read_alarm_internal() function.
181      *
182      * So, when the two timestamps disagree, we just loop and do
183      * the process again to get a fully consistent set of values.
184      *
185      * This could all instead be done in the lower level driver,
186      * but since more than one lower level RTC implementation needs it,
187      * then it's probably best best to do it here instead of there..
188      */
189 
190     /* Get the "before" timestamp */
191     err = rtc_read_time(rtc, &before);
192     if (err < 0)
193         return err;
194     do {
195         if (!first_time)
196             memcpy(&before, &now, sizeof(struct rtc_time));
197         first_time = 0;
198 
199         /* get the RTC alarm values, which may be incomplete */
200         err = rtc_read_alarm_internal(rtc, alarm);
201         if (err)
202             return err;
203         if (!alarm->enabled)
204             return 0;
205 
206         /* full-function RTCs won't have such missing fields */
207         if (rtc_valid_tm(&alarm->time) == 0)
208             return 0;
209 
210         /* get the "after" timestamp, to detect wrapped fields */
211         err = rtc_read_time(rtc, &now);
212         if (err < 0)
213             return err;
214 
215         /* note that tm_sec is a "don't care" value here: */
216     } while (   before.tm_min   != now.tm_min
217          || before.tm_hour  != now.tm_hour
218          || before.tm_mon   != now.tm_mon
219          || before.tm_year  != now.tm_year);
220 
221     /* Fill in the missing alarm fields using the timestamp; we
222      * know there's at least one since alarm->time is invalid.
223      */
224     if (alarm->time.tm_sec == -1)
225         alarm->time.tm_sec = now.tm_sec;
226     if (alarm->time.tm_min == -1)
227         alarm->time.tm_min = now.tm_min;
228     if (alarm->time.tm_hour == -1)
229         alarm->time.tm_hour = now.tm_hour;
230 
231     /* For simplicity, only support date rollover for now */
232     if (alarm->time.tm_mday == -1) {
233         alarm->time.tm_mday = now.tm_mday;
234         missing = day;
235     }
236     if (alarm->time.tm_mon == -1) {
237         alarm->time.tm_mon = now.tm_mon;
238         if (missing == none)
239             missing = month;
240     }
241     if (alarm->time.tm_year == -1) {
242         alarm->time.tm_year = now.tm_year;
243         if (missing == none)
244             missing = year;
245     }
246 
247     /* with luck, no rollover is needed */
248     rtc_tm_to_time(&now, &t_now);
249     rtc_tm_to_time(&alarm->time, &t_alm);
250     if (t_now < t_alm)
251         goto done;
252 
253     switch (missing) {
254 
255     /* 24 hour rollover ... if it's now 10am Monday, an alarm that
256      * that will trigger at 5am will do so at 5am Tuesday, which
257      * could also be in the next month or year.  This is a common
258      * case, especially for PCs.
259      */
260     case day:
261         dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day");
262         t_alm += 24 * 60 * 60;
263         rtc_time_to_tm(t_alm, &alarm->time);
264         break;
265 
266     /* Month rollover ... if it's the 31th, an alarm on the 3rd will
267      * be next month.  An alarm matching on the 30th, 29th, or 28th
268      * may end up in the month after that!  Many newer PCs support
269      * this type of alarm.
270      */
271     case month:
272         dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month");
273         do {
274             if (alarm->time.tm_mon < 11)
275                 alarm->time.tm_mon++;
276             else {
277                 alarm->time.tm_mon = 0;
278                 alarm->time.tm_year++;
279             }
280             days = rtc_month_days(alarm->time.tm_mon,
281                     alarm->time.tm_year);
282         } while (days < alarm->time.tm_mday);
283         break;
284 
285     /* Year rollover ... easy except for leap years! */
286     case year:
287         dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year");
288         do {
289             alarm->time.tm_year++;
290         } while (rtc_valid_tm(&alarm->time) != 0);
291         break;
292 
293     default:
294         dev_warn(&rtc->dev, "alarm rollover not handled\n");
295     }
296 
297 done:
298     return 0;
299 }
300 EXPORT_SYMBOL_GPL(rtc_read_alarm);
301 
302 int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
303 {
304     int err;
305 
306     err = rtc_valid_tm(&alarm->time);
307     if (err != 0)
308         return err;
309 
310     err = mutex_lock_interruptible(&rtc->ops_lock);
311     if (err)
312         return err;
313 
314     if (!rtc->ops)
315         err = -ENODEV;
316     else if (!rtc->ops->set_alarm)
317         err = -EINVAL;
318     else
319         err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
320 
321     mutex_unlock(&rtc->ops_lock);
322     return err;
323 }
324 EXPORT_SYMBOL_GPL(rtc_set_alarm);
325 
326 int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
327 {
328     int err = mutex_lock_interruptible(&rtc->ops_lock);
329     if (err)
330         return err;
331 
332     if (!rtc->ops)
333         err = -ENODEV;
334     else if (!rtc->ops->alarm_irq_enable)
335         err = -EINVAL;
336     else
337         err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled);
338 
339     mutex_unlock(&rtc->ops_lock);
340     return err;
341 }
342 EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable);
343 
344 int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
345 {
346     int err = mutex_lock_interruptible(&rtc->ops_lock);
347     if (err)
348         return err;
349 
350 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
351     if (enabled == 0 && rtc->uie_irq_active) {
352         mutex_unlock(&rtc->ops_lock);
353         return rtc_dev_update_irq_enable_emul(rtc, enabled);
354     }
355 #endif
356 
357     if (!rtc->ops)
358         err = -ENODEV;
359     else if (!rtc->ops->update_irq_enable)
360         err = -EINVAL;
361     else
362         err = rtc->ops->update_irq_enable(rtc->dev.parent, enabled);
363 
364     mutex_unlock(&rtc->ops_lock);
365 
366 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
367     /*
368      * Enable emulation if the driver did not provide
369      * the update_irq_enable function pointer or if returned
370      * -EINVAL to signal that it has been configured without
371      * interrupts or that are not available at the moment.
372      */
373     if (err == -EINVAL)
374         err = rtc_dev_update_irq_enable_emul(rtc, enabled);
375 #endif
376     return err;
377 }
378 EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
379 
380 /**
381  * rtc_update_irq - report RTC periodic, alarm, and/or update irqs
382  * @rtc: the rtc device
383  * @num: how many irqs are being reported (usually one)
384  * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF
385  * Context: any
386  */
387 void rtc_update_irq(struct rtc_device *rtc,
388         unsigned long num, unsigned long events)
389 {
390     unsigned long flags;
391 
392     spin_lock_irqsave(&rtc->irq_lock, flags);
393     rtc->irq_data = (rtc->irq_data + (num << 8)) | events;
394     spin_unlock_irqrestore(&rtc->irq_lock, flags);
395 
396     spin_lock_irqsave(&rtc->irq_task_lock, flags);
397     if (rtc->irq_task)
398         rtc->irq_task->func(rtc->irq_task->private_data);
399     spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
400 
401     wake_up_interruptible(&rtc->irq_queue);
402     kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
403 }
404 EXPORT_SYMBOL_GPL(rtc_update_irq);
405 
406 static int __rtc_match(struct device *dev, void *data)
407 {
408     char *name = (char *)data;
409 
410     if (strcmp(dev_name(dev), name) == 0)
411         return 1;
412     return 0;
413 }
414 
415 struct rtc_device *rtc_class_open(char *name)
416 {
417     struct device *dev;
418     struct rtc_device *rtc = NULL;
419 
420     dev = class_find_device(rtc_class, NULL, name, __rtc_match);
421     if (dev)
422         rtc = to_rtc_device(dev);
423 
424     if (rtc) {
425         if (!try_module_get(rtc->owner)) {
426             put_device(dev);
427             rtc = NULL;
428         }
429     }
430 
431     return rtc;
432 }
433 EXPORT_SYMBOL_GPL(rtc_class_open);
434 
435 void rtc_class_close(struct rtc_device *rtc)
436 {
437     module_put(rtc->owner);
438     put_device(&rtc->dev);
439 }
440 EXPORT_SYMBOL_GPL(rtc_class_close);
441 
442 int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task)
443 {
444     int retval = -EBUSY;
445 
446     if (task == NULL || task->func == NULL)
447         return -EINVAL;
448 
449     /* Cannot register while the char dev is in use */
450     if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags))
451         return -EBUSY;
452 
453     spin_lock_irq(&rtc->irq_task_lock);
454     if (rtc->irq_task == NULL) {
455         rtc->irq_task = task;
456         retval = 0;
457     }
458     spin_unlock_irq(&rtc->irq_task_lock);
459 
460     clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
461 
462     return retval;
463 }
464 EXPORT_SYMBOL_GPL(rtc_irq_register);
465 
466 void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
467 {
468     spin_lock_irq(&rtc->irq_task_lock);
469     if (rtc->irq_task == task)
470         rtc->irq_task = NULL;
471     spin_unlock_irq(&rtc->irq_task_lock);
472 }
473 EXPORT_SYMBOL_GPL(rtc_irq_unregister);
474 
475 /**
476  * rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs
477  * @rtc: the rtc device
478  * @task: currently registered with rtc_irq_register()
479  * @enabled: true to enable periodic IRQs
480  * Context: any
481  *
482  * Note that rtc_irq_set_freq() should previously have been used to
483  * specify the desired frequency of periodic IRQ task->func() callbacks.
484  */
485 int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled)
486 {
487     int err = 0;
488     unsigned long flags;
489 
490     if (rtc->ops->irq_set_state == NULL)
491         return -ENXIO;
492 
493     spin_lock_irqsave(&rtc->irq_task_lock, flags);
494     if (rtc->irq_task != NULL && task == NULL)
495         err = -EBUSY;
496     if (rtc->irq_task != task)
497         err = -EACCES;
498     spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
499 
500     if (err == 0)
501         err = rtc->ops->irq_set_state(rtc->dev.parent, enabled);
502 
503     return err;
504 }
505 EXPORT_SYMBOL_GPL(rtc_irq_set_state);
506 
507 /**
508  * rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ
509  * @rtc: the rtc device
510  * @task: currently registered with rtc_irq_register()
511  * @freq: positive frequency with which task->func() will be called
512  * Context: any
513  *
514  * Note that rtc_irq_set_state() is used to enable or disable the
515  * periodic IRQs.
516  */
517 int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
518 {
519     int err = 0;
520     unsigned long flags;
521 
522     if (rtc->ops->irq_set_freq == NULL)
523         return -ENXIO;
524 
525     spin_lock_irqsave(&rtc->irq_task_lock, flags);
526     if (rtc->irq_task != NULL && task == NULL)
527         err = -EBUSY;
528     if (rtc->irq_task != task)
529         err = -EACCES;
530     spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
531 
532     if (err == 0) {
533         err = rtc->ops->irq_set_freq(rtc->dev.parent, freq);
534         if (err == 0)
535             rtc->irq_freq = freq;
536     }
537     return err;
538 }
539 EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
interface.c

 

rtc-sysfs.c源代码:

  1 /*
  2  * RTC subsystem, sysfs interface
  3  *
  4  * Copyright (C) 2005 Tower Technologies
  5  * Author: Alessandro Zummo <a.zummo@towertech.it>
  6  *
  7  * This program is free software; you can redistribute it and/or modify
  8  * it under the terms of the GNU General Public License version 2 as
  9  * published by the Free Software Foundation.
 10 本文主要工作:
 11 1.在init给rtc时钟增加闹钟属性
 12 2.初始化一个struct device_attribute rtc_attrs[]属性结构体数组
 13 3.在函数rtc_sysfs_add_device中增加闹钟属性文件
 14 4.在函数rtc_sysfs_del_device中删除闹钟属性文件
 15 */
 16 
 17 #include <linux/module.h>
 18 #include <linux/rtc.h>
 19 
 20 #include "rtc-core.h"
 21 
 22 
 23 /* device attributes */
 24 
 25 /*
 26  * NOTE:  RTC times displayed in sysfs use the RTC's timezone.  That's
 27  * ideally UTC.  However, PCs that also boot to MS-Windows normally use
 28  * the local time and change to match daylight savings time.  That affects
 29  * attributes including date, time, since_epoch, and wakealarm.
 30  */
 31 
 32 static ssize_t
 33 rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr,
 34         char *buf)
 35 {
 36     return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
 37 }
 38 
 39 static ssize_t
 40 rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr,
 41         char *buf)
 42 {
 43     ssize_t retval;
 44     struct rtc_time tm;
 45 
 46     retval = rtc_read_time(to_rtc_device(dev), &tm);
 47     if (retval == 0) {
 48         retval = sprintf(buf, "%04d-%02d-%02d\n",
 49             tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
 50     }
 51 
 52     return retval;
 53 }
 54 
 55 static ssize_t
 56 rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr,
 57         char *buf)
 58 {
 59     ssize_t retval;
 60     struct rtc_time tm;
 61 
 62     retval = rtc_read_time(to_rtc_device(dev), &tm);
 63     if (retval == 0) {
 64         retval = sprintf(buf, "%02d:%02d:%02d\n",
 65             tm.tm_hour, tm.tm_min, tm.tm_sec);
 66     }
 67 
 68     return retval;
 69 }
 70 
 71 static ssize_t
 72 rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr,
 73         char *buf)
 74 {
 75     ssize_t retval;
 76     struct rtc_time tm;
 77 
 78     retval = rtc_read_time(to_rtc_device(dev), &tm);
 79     if (retval == 0) {
 80         unsigned long time;
 81         rtc_tm_to_time(&tm, &time);
 82         retval = sprintf(buf, "%lu\n", time);
 83     }
 84 
 85     return retval;
 86 }
 87 
 88 static ssize_t
 89 rtc_sysfs_show_max_user_freq(struct device *dev, struct device_attribute *attr,
 90         char *buf)
 91 {
 92     return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq);
 93 }
 94 
 95 static ssize_t
 96 rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr,
 97         const char *buf, size_t n)
 98 {
 99     struct rtc_device *rtc = to_rtc_device(dev);
100     unsigned long val = simple_strtoul(buf, NULL, 0);
101 
102     if (val >= 4096 || val == 0)
103         return -EINVAL;
104 
105     rtc->max_user_freq = (int)val;
106 
107     return n;
108 }
109 
110 static struct device_attribute rtc_attrs[] = {
111     __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
112     __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
113     __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),
114     __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),
115     __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq,
116             rtc_sysfs_set_max_user_freq),
117     { },
118 };
119 
120 static ssize_t
121 rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr,
122         char *buf)
123 {
124     ssize_t retval;
125     unsigned long alarm;
126     struct rtc_wkalrm alm;
127 
128     /* Don't show disabled alarms.  For uniformity, RTC alarms are
129      * conceptually one-shot, even though some common RTCs (on PCs)
130      * don't actually work that way.
131      *
132      * NOTE: RTC implementations where the alarm doesn't match an
133      * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC
134      * alarms after they trigger, to ensure one-shot semantics.
135      */
136     retval = rtc_read_alarm(to_rtc_device(dev), &alm);
137     if (retval == 0 && alm.enabled) {
138         rtc_tm_to_time(&alm.time, &alarm);
139         retval = sprintf(buf, "%lu\n", alarm);
140     }
141 
142     return retval;
143 }
144 
145 static ssize_t
146 rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr,
147         const char *buf, size_t n)
148 {
149     ssize_t retval;
150     unsigned long now, alarm;
151     struct rtc_wkalrm alm;
152     struct rtc_device *rtc = to_rtc_device(dev);
153     char *buf_ptr;
154     int adjust = 0;
155 
156     /* Only request alarms that trigger in the future.  Disable them
157      * by writing another time, e.g. 0 meaning Jan 1 1970 UTC.
158      */
159     retval = rtc_read_time(rtc, &alm.time);
160     if (retval < 0)
161         return retval;
162     rtc_tm_to_time(&alm.time, &now);
163 
164     buf_ptr = (char *)buf;
165     if (*buf_ptr == '+') {
166         buf_ptr++;
167         adjust = 1;
168     }
169     alarm = simple_strtoul(buf_ptr, NULL, 0);
170     if (adjust) {
171         alarm += now;
172     }
173     if (alarm > now) {
174         /* Avoid accidentally clobbering active alarms; we can't
175          * entirely prevent that here, without even the minimal
176          * locking from the /dev/rtcN api.
177          */
178         retval = rtc_read_alarm(rtc, &alm);
179         if (retval < 0)
180             return retval;
181         if (alm.enabled)
182             return -EBUSY;
183 
184         alm.enabled = 1;
185     } else {
186         alm.enabled = 0;
187 
188         /* Provide a valid future alarm time.  Linux isn't EFI,
189          * this time won't be ignored when disabling the alarm.
190          */
191         alarm = now + 300;
192     }
193     rtc_time_to_tm(alarm, &alm.time);
194 
195     retval = rtc_set_alarm(rtc, &alm);
196     return (retval < 0) ? retval : n;
197 }
198 static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR,
199         rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm);
200 
201 
202 /* The reason to trigger an alarm with no process watching it (via sysfs)
203  * is its side effect:  waking from a system state like suspend-to-RAM or
204  * suspend-to-disk.  So: no attribute unless that side effect is possible.
205  * (Userspace may disable that mechanism later.)
206  */
207 static inline int rtc_does_wakealarm(struct rtc_device *rtc)
208 {
209     if (!device_can_wakeup(rtc->dev.parent))
210         return 0;
211     return rtc->ops->set_alarm != NULL;
212 }
213 
214 
215 void rtc_sysfs_add_device(struct rtc_device *rtc)
216 {
217     int err;
218 
219     /* not all RTCs support both alarms and wakeup */
220     if (!rtc_does_wakealarm(rtc))
221         return;
222 
223     err = device_create_file(&rtc->dev, &dev_attr_wakealarm);
224     if (err)
225         dev_err(rtc->dev.parent,
226             "failed to create alarm attribute, %d\n", err);
227 }
228 
229 void rtc_sysfs_del_device(struct rtc_device *rtc)
230 {
231     /* REVISIT did we add it successfully? */
232     if (rtc_does_wakealarm(rtc))
233         device_remove_file(&rtc->dev, &dev_attr_wakealarm);
234 }
235 
236 void __init rtc_sysfs_init(struct class *rtc_class)
237 {
238     rtc_class->dev_attrs = rtc_attrs; //给rtc的类dev_attrs赋值rtc_attrs这个属性指针
239 }
rtc-sysfs.c

 

rtc-proc.c源代码:

  1 /*
  2  * RTC subsystem, proc interface
  3  *
  4  * Copyright (C) 2005-06 Tower Technologies
  5  * Author: Alessandro Zummo <a.zummo@towertech.it>
  6  *
  7  * based on arch/arm/common/rtctime.c
  8  *
  9  * This program is free software; you can redistribute it and/or modify
 10  * it under the terms of the GNU General Public License version 2 as
 11  * published by the Free Software Foundation.
 12 */
 13 
 14 #include <linux/module.h>
 15 #include <linux/rtc.h>
 16 #include <linux/proc_fs.h>
 17 #include <linux/seq_file.h>
 18 
 19 #include "rtc-core.h"
 20 
 21 
 22 static int rtc_proc_show(struct seq_file *seq, void *offset)
 23 {
 24     int err;
 25     struct rtc_device *rtc = seq->private;
 26     const struct rtc_class_ops *ops = rtc->ops;
 27     struct rtc_wkalrm alrm;
 28     struct rtc_time tm;
 29 
 30     err = rtc_read_time(rtc, &tm);
 31     if (err == 0) {
 32         seq_printf(seq,
 33             "rtc_time\t: %02d:%02d:%02d\n"
 34             "rtc_date\t: %04d-%02d-%02d\n",
 35             tm.tm_hour, tm.tm_min, tm.tm_sec,
 36             tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
 37     }
 38 
 39     err = rtc_read_alarm(rtc, &alrm);
 40     if (err == 0) {
 41         seq_printf(seq, "alrm_time\t: ");
 42         if ((unsigned int)alrm.time.tm_hour <= 24)
 43             seq_printf(seq, "%02d:", alrm.time.tm_hour);
 44         else
 45             seq_printf(seq, "**:");
 46         if ((unsigned int)alrm.time.tm_min <= 59)
 47             seq_printf(seq, "%02d:", alrm.time.tm_min);
 48         else
 49             seq_printf(seq, "**:");
 50         if ((unsigned int)alrm.time.tm_sec <= 59)
 51             seq_printf(seq, "%02d\n", alrm.time.tm_sec);
 52         else
 53             seq_printf(seq, "**\n");
 54 
 55         seq_printf(seq, "alrm_date\t: ");
 56         if ((unsigned int)alrm.time.tm_year <= 200)
 57             seq_printf(seq, "%04d-", alrm.time.tm_year + 1900);
 58         else
 59             seq_printf(seq, "****-");
 60         if ((unsigned int)alrm.time.tm_mon <= 11)
 61             seq_printf(seq, "%02d-", alrm.time.tm_mon + 1);
 62         else
 63             seq_printf(seq, "**-");
 64         if (alrm.time.tm_mday && (unsigned int)alrm.time.tm_mday <= 31)
 65             seq_printf(seq, "%02d\n", alrm.time.tm_mday);
 66         else
 67             seq_printf(seq, "**\n");
 68         seq_printf(seq, "alarm_IRQ\t: %s\n",
 69                 alrm.enabled ? "yes" : "no");
 70         seq_printf(seq, "alrm_pending\t: %s\n",
 71                 alrm.pending ? "yes" : "no");
 72     }
 73 
 74     seq_printf(seq, "24hr\t\t: yes\n");
 75 
 76     if (ops->proc)
 77         ops->proc(rtc->dev.parent, seq);
 78 
 79     return 0;
 80 }
 81 
 82 static int rtc_proc_open(struct inode *inode, struct file *file)
 83 {
 84     struct rtc_device *rtc = PDE(inode)->data;
 85 
 86     if (!try_module_get(THIS_MODULE))
 87         return -ENODEV;
 88 
 89     return single_open(file, rtc_proc_show, rtc);
 90 }
 91 
 92 static int rtc_proc_release(struct inode *inode, struct file *file)
 93 {
 94     int res = single_release(inode, file);
 95     module_put(THIS_MODULE);
 96     return res;
 97 }
 98 
 99 static const struct file_operations rtc_proc_fops = {
100     .open        = rtc_proc_open,
101     .read        = seq_read,
102     .llseek        = seq_lseek,
103     .release    = rtc_proc_release,
104 };
105 
106 void rtc_proc_add_device(struct rtc_device *rtc)
107 {
108     if (rtc->id == 0)
109         proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc);
110     //proc_create_data完成创建文件节点的作用,并将文件的操作函数与节点联系起来
111 }
112 
113 void rtc_proc_del_device(struct rtc_device *rtc)
114 {
115     if (rtc->id == 0)
116         remove_proc_entry("driver/rtc", NULL);
117 }
rtc-proc.c

 

转载于:https://www.cnblogs.com/lihaiyan/p/4318947.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值