RTC源代码分析

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

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

class.c源代码:

  1 /*
  2  * RTC subsystem, base class
  3  *
  4  * Copyright (C) 2005 Tower Technologies
  5  * Author: Alessandro Zummo <[email protected]>
  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 <[email protected]>");
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 <[email protected]>
  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 <[email protected]>
  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 <[email protected]>
  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 <[email protected]>
  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

时间: 2024-10-13 02:11:36

RTC源代码分析的相关文章

Java中arraylist和linkedlist源代码分析与性能比較

Java中arraylist和linkedlist源代码分析与性能比較 1,简单介绍 在java开发中比較经常使用的数据结构是arraylist和linkedlist,本文主要从源代码角度分析arraylist和linkedlist的性能. 2,arraylist源代码分析 Arraylist底层的数据结构是一个对象数组.有一个size的成员变量标记数组中元素的个数,例如以下图: * The array buffer into which the elements of the ArrayLis

转:RTMPDump源代码分析

0: 主要函数调用分析 rtmpdump 是一个用来处理 RTMP 流媒体的开源工具包,支持 rtmp://, rtmpt://, rtmpe://, rtmpte://, and rtmps://.也提供 Android 版本. 最近研究了一下它内部函数调用的关系. 下面列出几个主要的函数的调用关系. RTMPDump用于下载RTMP流媒体的函数Download: 用于建立网络连接(NetConnect)的函数Connect: 用于建立网络流(NetStream)的函数 rtmpdump源代码

Kafka SocketServer源代码分析

Kafka SocketServer源代码分析 标签: kafka 本文将详细分析Kafka SocketServer的相关源码. 总体设计 Kafka SocketServer是基于Java NIO来开发的,采用了Reactor的模式,其中包含了1个Acceptor负责接受客户端请求,N个Processor负责读写数据,M个Handler来处理业务逻辑.在Acceptor和Processor,Processor和Handler之间都有队列来缓冲请求. kafka.network.Accepto

pomelo源代码分析(一)

千里之行始于足下,一直说想了解pomelo,对pomelo有兴趣,但一直迟迟没有去碰,尽管对pomelo进行源代码分析,在网络上肯定不止我一个,已经有非常优秀的前辈走在前面,如http://golanger.cn/,在阅读Pomelo代码的时候,已经连载到了11篇了,在我的源代码分析參考了该博客,当然,也会添?我对pomelo的理解,借此希望能提高一下自己对node.js的了解和学习一些优秀的设计. 开发环境:win7 调试环境:webstorm5.0 node.js版本号:v0.8.21 源代

Jafka源代码分析——随笔

Kafka是一个分布式的消息中间件,可以粗略的将其划分为三部分:Producer.Broker和Consumer.其中,Producer负责产生消息并负责将消息发送给Kafka:Broker可以简单的理解为Kafka集群中的每一台机器,其负责完成消息队列的主要功能(接收消息.消息的持久化存储.为Consumer提供消息.消息清理.....):Consumer从Broker获取消息并进行后续的操作.每个broker会有一个ID标识,该标识由人工在配置文件中配置. Kafka中的消息隶属于topic

ftp server源代码分析20140602

当前是有些工具比如apktool,dextojar等是可以对我们android安装包进行反编译,获得源码的.为了减少被别人破解,导致源码泄露,程序被别人盗取代码,等等.我们需要对代码进行混淆,android的sdk中为我们提供了ProGrard这个工具,可以对代码进行混淆(一般是用无意义的名字来重命名),以及去除没有使用到的代码,对程序进行优化和压缩,这样可以增加你想的难度.最近我做的项目,是我去配置的混淆配置,因此研究了一下,这里分享一下. 如何启用ProGuard ant项目和eclipse

Spark SQL之External DataSource外部数据源(二)源代码分析

上周Spark1.2刚公布,周末在家没事,把这个特性给了解一下,顺便分析下源代码,看一看这个特性是怎样设计及实现的. /** Spark SQL源代码分析系列文章*/ (Ps: External DataSource使用篇地址:Spark SQL之External DataSource外部数据源(一)演示样例 http://blog.csdn.net/oopsoom/article/details/42061077) 一.Sources包核心 Spark SQL在Spark1.2中提供了Exte

【转载】linux环境下tcpdump源代码分析

linux环境下tcpdump源代码分析 原文时间 2013-10-11 13:13:02   原文链接   主题 Tcpdump 作者:韩大卫 @ 吉林师范大学 tcpdump.c 是tcpdump 工具的main.c, 本文旨对tcpdump的框架有简单了解,只展示linux平台使用的一部分核心代码. Tcpdump 的使用目的就是打印出指定条件的报文,即使有再多的正则表达式作为过滤条件.所以只要懂得tcpdump -nXXi eth0 的实现原理即可. 进入main之前,先看一些头文件 n

Android万能适配器base-adapter-helper的源代码分析

项目地址:https://github.com/JoanZapata/base-adapter-helper 1. 功能介绍 1.1. base-adapter-helper base-adapter-helper 是对传统的 BaseAdapter ViewHolder 模式的一个封装.主要功能就是简化我们书写 AbsListView 的 Adapter 的代码,如 ListView,GridView. 1.2 基本使用 mListView.setAdapter(mAdapter = new