• 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
  • 相关阅读:
    Linux-exec族函数
    Linux-竟态初步引入
    Linux-waitpid介绍
    Java基础:Java运算符:算术运算符
    Java中的算术运算符
    JAVA冒泡排序
    引用 java的一些基本概念
    Tomcat服务器的下载安装跟基本配置
    Tomcat配置Web站点
    Tomcat+JSP经典配置实例
  • 原文地址:https://www.cnblogs.com/lihaiyan/p/4318947.html
Copyright © 2020-2023  润新知