zoukankan      html  css  js  c++  java
  • 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
    ", 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!
    ", 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
    ",
    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
    ",
    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
    ", __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
    ", 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
    ",
    514             rtc->name, MAJOR(rtc_devt), rtc->id);
    515     else
    516         pr_debug("%s: dev (%d:%d)
    ", 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
    ",
    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
    ", "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
    ", "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
    ", "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
    ");
    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
    ", 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
    ",
     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
    ",
     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
    ", 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
    ", 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
    ", 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
    ", 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	: %02d:%02d:%02d
    "
     34             "rtc_date	: %04d-%02d-%02d
    ",
     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	: ");
     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
    ", alrm.time.tm_sec);
     52         else
     53             seq_printf(seq, "**
    ");
     54 
     55         seq_printf(seq, "alrm_date	: ");
     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
    ", alrm.time.tm_mday);
     66         else
     67             seq_printf(seq, "**
    ");
     68         seq_printf(seq, "alarm_IRQ	: %s
    ",
     69                 alrm.enabled ? "yes" : "no");
     70         seq_printf(seq, "alrm_pending	: %s
    ",
     71                 alrm.pending ? "yes" : "no");
     72     }
     73 
     74     seq_printf(seq, "24hr		: yes
    ");
     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
  • 相关阅读:
    笔记35 跨重定向请求传递数
    判断邮箱的正则表达式
    按钮
    async await 的用法
    笔记34 Spring MVC的高级技术——处理multipart形式的数据
    Convert Sorted Array to Binary Search Tree
    Binary Tree Zigzag Level Order Traversal
    Unique Binary Search Trees,Unique Binary Search Trees II
    Validate Binary Search Tree
    Populating Next Right Pointers in Each Node,Populating Next Right Pointers in Each Node II
  • 原文地址:https://www.cnblogs.com/lihaiyan/p/4318947.html
Copyright © 2011-2022 走看看