标签:
花了一个下午时间,把rtc代码的架构弄懂了,如下图所示:
下面附上各个包含详细注释的C文件源代码:
class.c源代码:
1 /* 2 * RTC subsystem, base class 3 * 4 * Copyright (C) 2005 Tower Technologies 5 * Author: Alessandro Zummo <a.zummo@towertech.it> 6 * 7 * class skeleton from drivers/hwmon/hwmon.c 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 本c文件工作总结: 13 1.在init函数中: 14 (1):创建sysfs文件系统的/sys/class/rtc目录,并且初始化rtc类的相关成员 15 作用:向用户空间提供设备的信息,驱动程序不需要直接处理类 16 (2):动态分配rtc字符设备的设备号 17 (3):初始化rtc的/sys/class/rtc目录中的属性文件 18 2.在exit函数中: 19 (1):注销rtc设备号 20 (2):注销sysfs文件系统的/sys/class/rtc目录。 21 3.在rtc_device_register中 22 (1):申请一个idr整数ID管理机制结构体,并且初始化相关成员 23 (2):将设备dev关联sysfs下的rtc类 24 (3):初始化rtc结构体的信号量 25 (4):初始化rtc结构体中的中断 26 (5):设置rtc的名字 27 (6):初始化rtc字符设备的设备号,然后注册rtc设备,自动创建/dev/rtc(n)设备节点文件 28 (7):注册字符设备 29 (8):在/sys/rtc/目录下创建一个闹钟属性文件 30 (9):创建/proc/driver/rtc目录 31 4.在rtc_device_unregister中 32 (1):删除sysfs中的rtc设备,即删除/sys/class/rtc目录 33 (2):删除dev下的/dev/rtc(n)设备节点文件 34 (3):删除虚拟文件系统接口,即删除/proc/driver/rtc目录 35 (4):卸载字符设备 36 (5):清空rtc的操作函数指针rtc->ops 37 (6):释放rtc的device结构体 38 5.在rtc_device_release函数中 39 (1):卸载idr数字管理机制结构体 40 (2):释放rtc结构体的内存 41 */ 42 43 #include <linux/module.h> 44 #include <linux/rtc.h> 45 #include <linux/kdev_t.h> 46 #include <linux/idr.h> 47 48 #include "rtc-core.h" 49 static DEFINE_MUTEX 50 51 static DEFINE_IDR(rtc_idr); //定义整数ID管理机制idr结构体 52 (idr_lock); 53 struct class *rtc_class; //定义sysfs的类结构体 54 55 static void rtc_device_release(struct device *dev) 56 { 57 struct rtc_device *rtc = to_rtc_device(dev); 58 mutex_lock(&idr_lock); 59 idr_remove(&rtc_idr, rtc->id); //卸载idr数字管理机制结构体 60 mutex_unlock(&idr_lock); 61 kfree(rtc); //释放rtc结构体的内存 62 } 63 64 #if defined(CONFIG_PM) && defined(CONFIG_RTC_HCTOSYS_DEVICE) 65 66 /* 67 * On suspend(), measure the delta between one RTC and the 68 * system‘s wall clock; restore it on resume(). 69 */ 70 71 static struct timespec delta; 72 static time_t oldtime; 73 74 static int rtc_suspend(struct device *dev, pm_message_t mesg) 75 { 76 struct rtc_device *rtc = to_rtc_device(dev); 77 struct rtc_time tm; 78 struct timespec ts = current_kernel_time(); 79 80 if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) 81 return 0; 82 83 rtc_read_time(rtc, &tm); 84 rtc_tm_to_time(&tm, &oldtime); 85 86 /* RTC precision is 1 second; adjust delta for avg 1/2 sec err */ 87 set_normalized_timespec(&delta, 88 ts.tv_sec - oldtime, 89 ts.tv_nsec - (NSEC_PER_SEC >> 1)); 90 91 return 0; 92 } 93 94 static int rtc_resume(struct device *dev) 95 { 96 struct rtc_device *rtc = to_rtc_device(dev); 97 struct rtc_time tm; 98 time_t newtime; 99 struct timespec time; 100 101 if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) 102 return 0; 103 104 rtc_read_time(rtc, &tm); 105 if (rtc_valid_tm(&tm) != 0) { 106 pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev)); 107 return 0; 108 } 109 rtc_tm_to_time(&tm, &newtime); 110 if (newtime <= oldtime) { 111 if (newtime < oldtime) 112 pr_debug("%s: time travel!\n", dev_name(&rtc->dev)); 113 return 0; 114 } 115 116 /* restore wall clock using delta against this RTC; 117 * adjust again for avg 1/2 second RTC sampling error 118 */ 119 set_normalized_timespec(&time, 120 newtime + delta.tv_sec, 121 (NSEC_PER_SEC >> 1) + delta.tv_nsec); 122 do_settimeofday(&time); 123 124 return 0; 125 } 126 127 #else 128 #define rtc_suspend NULL 129 #define rtc_resume NULL 130 #endif 131 132 133 /** 134 * rtc_device_register - register w/ RTC class 135 * @dev: the device to register 136 * 137 * rtc_device_unregister() must be called when the class device is no 138 * longer needed. 139 * 140 * Returns the pointer to the new struct class device. 141 */ 142 struct rtc_device *rtc_device_register(const char *name, struct device *dev, 143 const struct rtc_class_ops *ops, 144 struct module *owner) 145 { 146 struct rtc_device *rtc; 147 int id, err; 148 //整数ID管理机制 149 if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) { //检测IDR是否能正常获取 150 err = -ENOMEM; 151 goto exit; 152 } 153 154 155 mutex_lock(&idr_lock); //原子操作,上锁,防止被打断 156 err = idr_get_new(&rtc_idr, NULL, &id); //获取一个idr结构,并与id相关联 157 mutex_unlock(&idr_lock); //解锁 158 159 if (err < 0) 160 goto exit; 161 162 id = id & MAX_ID_MASK; //将32为id的无效高位清零 163 164 rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL); //分配一个rtc_device结构体 165 if (rtc == NULL) { 166 err = -ENOMEM; 167 goto exit_idr; 168 } 169 170 rtc->id = id; //整数ID管理机制 171 rtc->ops = ops; //关联定义的操作函数结构体 open,release,ioctl等函数 172 rtc->owner = owner; //所属模块的相关信息 173 rtc->max_user_freq = 64; //最大使用数量 64 174 rtc->dev.parent = dev; //父设备 175 rtc->dev.class = rtc_class; //包含的sysfs下面的类 176 rtc->dev.release = rtc_device_release; //释放函数 177 178 mutex_init(&rtc->ops_lock); //初始化信号量 179 spin_lock_init(&rtc->irq_lock); 180 spin_lock_init(&rtc->irq_task_lock); 181 init_waitqueue_head(&rtc->irq_queue); //定义rtc中断 182 183 strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); //设置rtc的名字 184 dev_set_name(&rtc->dev, "rtc%d", id); 185 186 rtc_dev_prepare(rtc); //初始化rtc字符设备的设备号 187 188 err = device_register(&rtc->dev); //注册rtc设备,这样rtc会自动创建设备文件rtc(n) 189 if (err) 190 goto exit_kfree; 191 192 rtc_dev_add_device(rtc); //注册字符设备 193 rtc_sysfs_add_device(rtc); //为设备添加一个闹钟属性,在/sys/rtc下面创建闹钟属性文件 194 rtc_proc_add_device(rtc); //穿件proc文件结构体 在/proc目录下创建 driver/rtc 195 196 dev_info(dev, "rtc core: registered %s as %s\n", 197 rtc->name, dev_name(&rtc->dev)); //打印信息 198 199 return rtc; 200 201 exit_kfree: 202 kfree(rtc); 203 204 exit_idr: 205 mutex_lock(&idr_lock); 206 idr_remove(&rtc_idr, id); 207 mutex_unlock(&idr_lock); 208 209 exit: 210 dev_err(dev, "rtc core: unable to register %s, err = %d\n", 211 name, err); 212 return ERR_PTR(err); 213 } 214 EXPORT_SYMBOL_GPL(rtc_device_register); 215 216 217 /** 218 * rtc_device_unregister - removes the previously registered RTC class device 219 * 220 * @rtc: the RTC class device to destroy 221 */ 222 void rtc_device_unregister(struct rtc_device *rtc) 223 { 224 if (get_device(&rtc->dev) != NULL) { 225 mutex_lock(&rtc->ops_lock); //上锁 226 /* remove innards of this RTC, then disable it, before 227 * letting any rtc_class_open() users access it again 228 */ 229 rtc_sysfs_del_device(rtc); //删除sysfs下面的rtc设备 230 rtc_dev_del_device(rtc); //删除dev下的rtc 231 rtc_proc_del_device(rtc); //删除虚拟文件系统接口 232 device_unregister(&rtc->dev); //卸载字符设备 233 rtc->ops = NULL; //将rtc的操作函数指针清空 234 mutex_unlock(&rtc->ops_lock); //解锁 235 put_device(&rtc->dev); //释放rtc的device结构体 236 } 237 } 238 EXPORT_SYMBOL_GPL(rtc_device_unregister); 239 240 static int __init rtc_init(void) 241 { 242 rtc_class = class_create(THIS_MODULE, "rtc");//在/sys/class下面创建类目录,类名为rtc 243 if (IS_ERR(rtc_class)) { 244 printk(KERN_ERR "%s: couldn‘t create class\n", __FILE__); 245 return PTR_ERR(rtc_class); 246 } 247 //类的作用就是向用户空间提供设备的信息,驱动程序不需要直接处理类 248 rtc_class->suspend = rtc_suspend; //初始化类结构体的相关成员 249 rtc_class->resume = rtc_resume; //动态分配rtc的设备号 250 rtc_dev_init(); //动态分配 251 rtc_sysfs_init(rtc_class); //初始化rtc的属性文件 252 return 0; 253 } 254 255 static void __exit rtc_exit(void) 256 { 257 rtc_dev_exit(); //注销rtc设备号 258 class_destroy(rtc_class); //注销/sys/class下的类目录 259 } 260 261 subsys_initcall(rtc_init); 262 module_exit(rtc_exit); 263 264 MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); 265 MODULE_DESCRIPTION("RTC class support"); 266 MODULE_LICENSE("GPL");
rtc-dev.c源代码:
1 /* 2 * RTC subsystem, dev interface 3 * 4 * Copyright (C) 2005 Tower Technologies 5 * Author: Alessandro Zummo <a.zummo@towertech.it> 6 * 7 * based on arch/arm/common/rtctime.c 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 13 本程序大致内容 14 1.在init函数中动态的申请字符设备的设备号 15 2.实现struct file_operations rtc_dev_fops 结构体及其默认函数 16 3.在exit中注销字符设备设备号 17 */ 18 19 #include <linux/module.h> 20 #include <linux/rtc.h> 21 #include "rtc-core.h" 22 23 static dev_t rtc_devt; 24 25 #define RTC_DEV_MAX 16 /* 16 RTCs should be enough for everyone... */ 26 27 static int rtc_dev_open(struct inode *inode, struct file *file) 28 { 29 int err; 30 struct rtc_device *rtc = container_of(inode->i_cdev, 31 struct rtc_device, char_dev); 32 const struct rtc_class_ops *ops = rtc->ops; 33 34 if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags)) 35 return -EBUSY; 36 37 file->private_data = rtc; 38 39 err = ops->open ? ops->open(rtc->dev.parent) : 0; 40 if (err == 0) { 41 spin_lock_irq(&rtc->irq_lock); 42 rtc->irq_data = 0; 43 spin_unlock_irq(&rtc->irq_lock); 44 45 return 0; 46 } 47 48 /* something has gone wrong */ 49 clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); 50 return err; 51 } 52 53 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL 54 /* 55 * Routine to poll RTC seconds field for change as often as possible, 56 * after first RTC_UIE use timer to reduce polling 57 */ 58 static void rtc_uie_task(struct work_struct *work) 59 { 60 struct rtc_device *rtc = 61 container_of(work, struct rtc_device, uie_task); 62 struct rtc_time tm; 63 int num = 0; 64 int err; 65 66 err = rtc_read_time(rtc, &tm); 67 68 spin_lock_irq(&rtc->irq_lock); 69 if (rtc->stop_uie_polling || err) { 70 rtc->uie_task_active = 0; 71 } else if (rtc->oldsecs != tm.tm_sec) { 72 num = (tm.tm_sec + 60 - rtc->oldsecs) % 60; 73 rtc->oldsecs = tm.tm_sec; 74 rtc->uie_timer.expires = jiffies + HZ - (HZ/10); 75 rtc->uie_timer_active = 1; 76 rtc->uie_task_active = 0; 77 add_timer(&rtc->uie_timer); 78 } else if (schedule_work(&rtc->uie_task) == 0) { 79 rtc->uie_task_active = 0; 80 } 81 spin_unlock_irq(&rtc->irq_lock); 82 if (num) 83 rtc_update_irq(rtc, num, RTC_UF | RTC_IRQF); 84 } 85 static void rtc_uie_timer(unsigned long data) 86 { 87 struct rtc_device *rtc = (struct rtc_device *)data; 88 unsigned long flags; 89 90 spin_lock_irqsave(&rtc->irq_lock, flags); 91 rtc->uie_timer_active = 0; 92 rtc->uie_task_active = 1; 93 if ((schedule_work(&rtc->uie_task) == 0)) 94 rtc->uie_task_active = 0; 95 spin_unlock_irqrestore(&rtc->irq_lock, flags); 96 } 97 98 static int clear_uie(struct rtc_device *rtc) 99 { 100 spin_lock_irq(&rtc->irq_lock); 101 if (rtc->uie_irq_active) { 102 rtc->stop_uie_polling = 1; 103 if (rtc->uie_timer_active) { 104 spin_unlock_irq(&rtc->irq_lock); 105 del_timer_sync(&rtc->uie_timer); 106 spin_lock_irq(&rtc->irq_lock); 107 rtc->uie_timer_active = 0; 108 } 109 if (rtc->uie_task_active) { 110 spin_unlock_irq(&rtc->irq_lock); 111 flush_scheduled_work(); 112 spin_lock_irq(&rtc->irq_lock); 113 } 114 rtc->uie_irq_active = 0; 115 } 116 spin_unlock_irq(&rtc->irq_lock); 117 return 0; 118 } 119 120 static int set_uie(struct rtc_device *rtc) 121 { 122 struct rtc_time tm; 123 int err; 124 125 err = rtc_read_time(rtc, &tm); 126 if (err) 127 return err; 128 spin_lock_irq(&rtc->irq_lock); 129 if (!rtc->uie_irq_active) { 130 rtc->uie_irq_active = 1; 131 rtc->stop_uie_polling = 0; 132 rtc->oldsecs = tm.tm_sec; 133 rtc->uie_task_active = 1; 134 if (schedule_work(&rtc->uie_task) == 0) 135 rtc->uie_task_active = 0; 136 } 137 rtc->irq_data = 0; 138 spin_unlock_irq(&rtc->irq_lock); 139 return 0; 140 } 141 142 int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled) 143 { 144 if (enabled) 145 return set_uie(rtc); 146 else 147 return clear_uie(rtc); 148 } 149 EXPORT_SYMBOL(rtc_dev_update_irq_enable_emul); 150 151 #endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */ 152 153 static ssize_t 154 rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) 155 { 156 struct rtc_device *rtc = file->private_data; 157 158 DECLARE_WAITQUEUE(wait, current); //声明一个等待队列入口 159 unsigned long data; 160 ssize_t ret; 161 162 if (count != sizeof(unsigned int) && count < sizeof(unsigned long)) 163 return -EINVAL; 164 165 add_wait_queue(&rtc->irq_queue, &wait);//将这个等待队列的入口加入到rtc的irq等待队列中 166 do { 167 __set_current_state(TASK_INTERRUPTIBLE);//把当前进程的状态修改为TASK_INTERRUPTIBLE 168 169 spin_lock_irq(&rtc->irq_lock); //保护代码段不被抢占(禁止 IRQ 同时也就隐式地禁止了抢占),既禁止本地中断,又禁止内核抢占。 170 data = rtc->irq_data; 171 rtc->irq_data = 0; 172 spin_unlock_irq(&rtc->irq_lock); 173 174 if (data != 0) { //如果数据不是零的话说明发生过一次中断 175 ret = 0; 176 break; 177 } 178 if (file->f_flags & O_NONBLOCK) { //如果打开方式为不阻塞的话,直接返回 179 ret = -EAGAIN; 180 break; 181 } 182 if (signal_pending(current)) { //检查当前进程是否有信号处理,返回不为0表示有信号需要处理。 183 ret = -ERESTARTSYS; 184 break; 185 } 186 schedule(); //如果没有发生过中断,并且也没有信号处理,则调度 187 } while (1); 188 set_current_state(TASK_RUNNING);//把当前进程的状态修改为TASK_RUNNING 189 190 remove_wait_queue(&rtc->irq_queue, &wait); //移除等待队列 191 192 if (ret == 0) { //如果发生过中断 193 /* Check for any data updates */ 194 if (rtc->ops->read_callback) 195 data = rtc->ops->read_callback(rtc->dev.parent, 196 data); 197 198 if (sizeof(int) != sizeof(long) && 199 count == sizeof(unsigned int)) 200 ret = put_user(data, (unsigned int __user *)buf) ?: 201 sizeof(unsigned int); 202 else 203 ret = put_user(data, (unsigned long __user *)buf) ?: 204 sizeof(unsigned long); 205 } 206 return ret; 207 } 208 209 static unsigned int rtc_dev_poll(struct file *file, poll_table *wait) 210 { 211 struct rtc_device *rtc = file->private_data; 212 unsigned long data; 213 214 poll_wait(file, &rtc->irq_queue, wait); //监控文件,加入等待队列 215 216 data = rtc->irq_data; 217 218 return (data != 0) ? (POLLIN | POLLRDNORM) : 0; 219 } 220 221 static long rtc_dev_ioctl(struct file *file, 222 unsigned int cmd, unsigned long arg) 223 { 224 int err = 0; 225 struct rtc_device *rtc = file->private_data; 226 const struct rtc_class_ops *ops = rtc->ops; 227 struct rtc_time tm; 228 struct rtc_wkalrm alarm; 229 void __user *uarg = (void __user *) arg; 230 231 err = mutex_lock_interruptible(&rtc->ops_lock); 232 if (err) 233 return err; 234 235 /* check that the calling task has appropriate permissions 236 * for certain ioctls. doing this check here is useful 237 * to avoid duplicate code in each driver. 238 */ 239 switch (cmd) { 240 case RTC_EPOCH_SET: 241 case RTC_SET_TIME: 242 if (!capable(CAP_SYS_TIME)) 243 err = -EACCES; 244 break; 245 246 case RTC_IRQP_SET: 247 if (arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE)) 248 err = -EACCES; 249 break; 250 251 case RTC_PIE_ON: 252 if (rtc->irq_freq > rtc->max_user_freq && 253 !capable(CAP_SYS_RESOURCE)) 254 err = -EACCES; 255 break; 256 } 257 258 if (err) 259 goto done; 260 261 /* try the driver‘s ioctl interface */ 262 if (ops->ioctl) { 263 err = ops->ioctl(rtc->dev.parent, cmd, arg); 264 if (err != -ENOIOCTLCMD) { 265 mutex_unlock(&rtc->ops_lock); 266 return err; 267 } 268 } 269 270 /* if the driver does not provide the ioctl interface 271 * or if that particular ioctl was not implemented 272 * (-ENOIOCTLCMD), we will try to emulate here. 273 * 274 * Drivers *SHOULD NOT* provide ioctl implementations 275 * for these requests. Instead, provide methods to 276 * support the following code, so that the RTC‘s main 277 * features are accessible without using ioctls. 278 * 279 * RTC and alarm times will be in UTC, by preference, 280 * but dual-booting with MS-Windows implies RTCs must 281 * use the local wall clock time. 282 */ 283 284 switch (cmd) { 285 case RTC_ALM_READ: 286 mutex_unlock(&rtc->ops_lock); 287 288 err = rtc_read_alarm(rtc, &alarm); 289 if (err < 0) 290 return err; 291 292 if (copy_to_user(uarg, &alarm.time, sizeof(tm))) 293 err = -EFAULT; 294 return err; 295 296 case RTC_ALM_SET: 297 mutex_unlock(&rtc->ops_lock); 298 299 if (copy_from_user(&alarm.time, uarg, sizeof(tm))) 300 return -EFAULT; 301 302 alarm.enabled = 0; 303 alarm.pending = 0; 304 alarm.time.tm_wday = -1; 305 alarm.time.tm_yday = -1; 306 alarm.time.tm_isdst = -1; 307 308 /* RTC_ALM_SET alarms may be up to 24 hours in the future. 309 * Rather than expecting every RTC to implement "don‘t care" 310 * for day/month/year fields, just force the alarm to have 311 * the right values for those fields. 312 * 313 * RTC_WKALM_SET should be used instead. Not only does it 314 * eliminate the need for a separate RTC_AIE_ON call, it 315 * doesn‘t have the "alarm 23:59:59 in the future" race. 316 * 317 * NOTE: some legacy code may have used invalid fields as 318 * wildcards, exposing hardware "periodic alarm" capabilities. 319 * Not supported here. 320 */ 321 { 322 unsigned long now, then; 323 324 err = rtc_read_time(rtc, &tm); 325 if (err < 0) 326 return err; 327 rtc_tm_to_time(&tm, &now); 328 329 alarm.time.tm_mday = tm.tm_mday; 330 alarm.time.tm_mon = tm.tm_mon; 331 alarm.time.tm_year = tm.tm_year; 332 err = rtc_valid_tm(&alarm.time); 333 if (err < 0) 334 return err; 335 rtc_tm_to_time(&alarm.time, &then); 336 337 /* alarm may need to wrap into tomorrow */ 338 if (then < now) { 339 rtc_time_to_tm(now + 24 * 60 * 60, &tm); 340 alarm.time.tm_mday = tm.tm_mday; 341 alarm.time.tm_mon = tm.tm_mon; 342 alarm.time.tm_year = tm.tm_year; 343 } 344 } 345 346 return rtc_set_alarm(rtc, &alarm); 347 348 case RTC_RD_TIME: 349 mutex_unlock(&rtc->ops_lock); 350 351 err = rtc_read_time(rtc, &tm); 352 if (err < 0) 353 return err; 354 355 if (copy_to_user(uarg, &tm, sizeof(tm))) 356 err = -EFAULT; 357 return err; 358 359 case RTC_SET_TIME: 360 mutex_unlock(&rtc->ops_lock); 361 362 if (copy_from_user(&tm, uarg, sizeof(tm))) 363 return -EFAULT; 364 365 return rtc_set_time(rtc, &tm); 366 367 case RTC_PIE_ON: 368 err = rtc_irq_set_state(rtc, NULL, 1); 369 break; 370 371 case RTC_PIE_OFF: 372 err = rtc_irq_set_state(rtc, NULL, 0); 373 break; 374 375 case RTC_AIE_ON: 376 mutex_unlock(&rtc->ops_lock); 377 return rtc_alarm_irq_enable(rtc, 1); 378 379 case RTC_AIE_OFF: 380 mutex_unlock(&rtc->ops_lock); 381 return rtc_alarm_irq_enable(rtc, 0); 382 383 case RTC_UIE_ON: 384 mutex_unlock(&rtc->ops_lock); 385 return rtc_update_irq_enable(rtc, 1); 386 387 case RTC_UIE_OFF: 388 mutex_unlock(&rtc->ops_lock); 389 return rtc_update_irq_enable(rtc, 0); 390 391 case RTC_IRQP_SET: 392 err = rtc_irq_set_freq(rtc, NULL, arg); 393 break; 394 395 case RTC_IRQP_READ: 396 err = put_user(rtc->irq_freq, (unsigned long __user *)uarg); 397 break; 398 399 #if 0 400 case RTC_EPOCH_SET: 401 #ifndef rtc_epoch 402 /* 403 * There were no RTC clocks before 1900. 404 */ 405 if (arg < 1900) { 406 err = -EINVAL; 407 break; 408 } 409 rtc_epoch = arg; 410 err = 0; 411 #endif 412 break; 413 414 case RTC_EPOCH_READ: 415 err = put_user(rtc_epoch, (unsigned long __user *)uarg); 416 break; 417 #endif 418 case RTC_WKALM_SET: 419 mutex_unlock(&rtc->ops_lock); 420 if (copy_from_user(&alarm, uarg, sizeof(alarm))) 421 return -EFAULT; 422 423 return rtc_set_alarm(rtc, &alarm); 424 425 case RTC_WKALM_RD: 426 mutex_unlock(&rtc->ops_lock); 427 err = rtc_read_alarm(rtc, &alarm); 428 if (err < 0) 429 return err; 430 431 if (copy_to_user(uarg, &alarm, sizeof(alarm))) 432 err = -EFAULT; 433 return err; 434 435 default: 436 err = -ENOTTY; 437 break; 438 } 439 440 done: 441 mutex_unlock(&rtc->ops_lock); 442 return err; 443 } 444 445 static int rtc_dev_fasync(int fd, struct file *file, int on) 446 { 447 struct rtc_device *rtc = file->private_data; 448 return fasync_helper(fd, file, on, &rtc->async_queue); 449 } 450 451 static int rtc_dev_release(struct inode *inode, struct file *file) 452 { 453 struct rtc_device *rtc = file->private_data; 454 455 /* We shut down the repeating IRQs that userspace enabled, 456 * since nothing is listening to them. 457 * - Update (UIE) ... currently only managed through ioctls 458 * - Periodic (PIE) ... also used through rtc_*() interface calls 459 * 460 * Leave the alarm alone; it may be set to trigger a system wakeup 461 * later, or be used by kernel code, and is a one-shot event anyway. 462 */ 463 464 /* Keep ioctl until all drivers are converted */ 465 rtc_dev_ioctl(file, RTC_UIE_OFF, 0); 466 rtc_update_irq_enable(rtc, 0); 467 rtc_irq_set_state(rtc, NULL, 0); 468 469 if (rtc->ops->release) 470 rtc->ops->release(rtc->dev.parent); 471 472 clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); 473 return 0; 474 } 475 476 static const struct file_operations rtc_dev_fops = { 477 .owner = THIS_MODULE, 478 .llseek = no_llseek, 479 .read = rtc_dev_read, 480 .poll = rtc_dev_poll, 481 .unlocked_ioctl = rtc_dev_ioctl, 482 .open = rtc_dev_open, 483 .release = rtc_dev_release, 484 .fasync = rtc_dev_fasync, 485 }; 486 487 /* insertion/removal hooks */ 488 489 void rtc_dev_prepare(struct rtc_device *rtc) 490 { 491 if (!rtc_devt) 492 return; 493 494 if (rtc->id >= RTC_DEV_MAX) { 495 pr_debug("%s: too many RTC devices\n", rtc->name); 496 return; 497 } 498 499 rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); //获取rtc的设备号 500 501 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL 502 INIT_WORK(&rtc->uie_task, rtc_uie_task); 503 setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc); 504 #endif 505 506 cdev_init(&rtc->char_dev, &rtc_dev_fops); 507 rtc->char_dev.owner = rtc->owner; 508 } 509 510 void rtc_dev_add_device(struct rtc_device *rtc) 511 { 512 if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1)) 513 printk(KERN_WARNING "%s: failed to add char device %d:%d\n", 514 rtc->name, MAJOR(rtc_devt), rtc->id); 515 else 516 pr_debug("%s: dev (%d:%d)\n", rtc->name, 517 MAJOR(rtc_devt), rtc->id); 518 } 519 520 void rtc_dev_del_device(struct rtc_device *rtc) 521 { 522 if (rtc->dev.devt) 523 cdev_del(&rtc->char_dev); 524 } 525 526 void __init rtc_dev_init(void) 527 { 528 int err; 529 530 err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc"); //动态分配rtc的设备号 531 if (err < 0) 532 printk(KERN_ERR "%s: failed to allocate char dev region\n", 533 __FILE__); 534 } 535 536 void __exit rtc_dev_exit(void) 537 { 538 if (rtc_devt) 539 unregister_chrdev_region(rtc_devt, RTC_DEV_MAX); //注销设备号 540 }
interface.c源代码:
1 /* 2 * RTC subsystem, interface functions 3 * 4 * Copyright (C) 2005 Tower Technologies 5 * Author: Alessandro Zummo <a.zummo@towertech.it> 6 * 7 * based on arch/arm/common/rtctime.c 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 13 本函数中主要就是实现 前面我们rtc-dev.c中ioctl的各种命令函数 14 RTC_ALM_READ rtc_read_alarm 读取闹钟时间 15 RTC_ALM_SET rtc_set_alarm 设置闹钟时间 16 RTC_RD_TIME rtc_read_time 读取时间与日期 17 RTC_SET_TIME rtc_set_time 设置时间与日期 18 RTC_PIE_ON RTC_PIE_OFF rtc_irq_set_state 开关RTC全局中断的函数 19 RTC_AIE_ON RTC_AIE_OFF rtc_alarm_irq_enable 使能禁止RTC闹钟中断 20 RTC_UIE_OFF RTC_UIE_ON rtc_update_irq_enable 使能禁止RTC更新中断 21 RTC_IRQP_SET rtc_irq_set_freq 设置中断的频率 22 23 */ 24 25 #include <linux/rtc.h> 26 #include <linux/log2.h> 27 28 int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) 29 { 30 int err; 31 32 err = mutex_lock_interruptible(&rtc->ops_lock); //上锁,用了一个信号来保证在同一时刻只有一个进程可以获取时间 33 if (err) 34 return err; 35 36 if (!rtc->ops) //如果rtc的ops结构体为空,则直接返回 37 err = -ENODEV; 38 else if (!rtc->ops->read_time) //如果未定义ops的read_time函数,直接返回 39 err = -EINVAL; 40 else { 41 memset(tm, 0, sizeof(struct rtc_time)); //将内存清零,清空tm结构体 42 err = rtc->ops->read_time(rtc->dev.parent, tm);//读取时间 43 } 44 45 mutex_unlock(&rtc->ops_lock);//解锁 46 return err; 47 } 48 EXPORT_SYMBOL_GPL(rtc_read_time); 49 50 int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) 51 { 52 int err; 53 54 err = rtc_valid_tm(tm); 55 if (err != 0) 56 return err; 57 58 err = mutex_lock_interruptible(&rtc->ops_lock); 59 if (err) 60 return err; 61 62 if (!rtc->ops) 63 err = -ENODEV; 64 else if (rtc->ops->set_time) 65 err = rtc->ops->set_time(rtc->dev.parent, tm); 66 else if (rtc->ops->set_mmss) { 67 unsigned long secs; 68 err = rtc_tm_to_time(tm, &secs); 69 if (err == 0) 70 err = rtc->ops->set_mmss(rtc->dev.parent, secs); 71 } else 72 err = -EINVAL; 73 74 mutex_unlock(&rtc->ops_lock); 75 return err; 76 } 77 EXPORT_SYMBOL_GPL(rtc_set_time); 78 79 int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) 80 { 81 int err; 82 83 err = mutex_lock_interruptible(&rtc->ops_lock); 84 if (err) 85 return err; 86 87 if (!rtc->ops) 88 err = -ENODEV; 89 else if (rtc->ops->set_mmss) 90 err = rtc->ops->set_mmss(rtc->dev.parent, secs); 91 else if (rtc->ops->read_time && rtc->ops->set_time) { 92 struct rtc_time new, old; 93 94 err = rtc->ops->read_time(rtc->dev.parent, &old); 95 if (err == 0) { 96 rtc_time_to_tm(secs, &new); 97 98 /* 99 * avoid writing when we‘re going to change the day of 100 * the month. We will retry in the next minute. This 101 * basically means that if the RTC must not drift 102 * by more than 1 minute in 11 minutes. 103 */ 104 if (!((old.tm_hour == 23 && old.tm_min == 59) || 105 (new.tm_hour == 23 && new.tm_min == 59))) 106 err = rtc->ops->set_time(rtc->dev.parent, 107 &new); 108 } 109 } 110 else 111 err = -EINVAL; 112 113 mutex_unlock(&rtc->ops_lock); 114 115 return err; 116 } 117 EXPORT_SYMBOL_GPL(rtc_set_mmss); 118 119 static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 120 { 121 int err; 122 123 err = mutex_lock_interruptible(&rtc->ops_lock); 124 if (err) 125 return err; 126 127 if (rtc->ops == NULL) 128 err = -ENODEV; 129 else if (!rtc->ops->read_alarm) 130 err = -EINVAL; 131 else { 132 memset(alarm, 0, sizeof(struct rtc_wkalrm)); 133 err = rtc->ops->read_alarm(rtc->dev.parent, alarm); 134 } 135 136 mutex_unlock(&rtc->ops_lock); 137 return err; 138 } 139 140 int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 141 { 142 int err; 143 struct rtc_time before, now; 144 int first_time = 1; 145 unsigned long t_now, t_alm; 146 enum { none, day, month, year } missing = none; 147 unsigned days; 148 149 /* The lower level RTC driver may return -1 in some fields, 150 * creating invalid alarm->time values, for reasons like: 151 * 152 * - The hardware may not be capable of filling them in; 153 * many alarms match only on time-of-day fields, not 154 * day/month/year calendar data. 155 * 156 * - Some hardware uses illegal values as "wildcard" match 157 * values, which non-Linux firmware (like a BIOS) may try 158 * to set up as e.g. "alarm 15 minutes after each hour". 159 * Linux uses only oneshot alarms. 160 * 161 * When we see that here, we deal with it by using values from 162 * a current RTC timestamp for any missing (-1) values. The 163 * RTC driver prevents "periodic alarm" modes. 164 * 165 * But this can be racey, because some fields of the RTC timestamp 166 * may have wrapped in the interval since we read the RTC alarm, 167 * which would lead to us inserting inconsistent values in place 168 * of the -1 fields. 169 * 170 * Reading the alarm and timestamp in the reverse sequence 171 * would have the same race condition, and not solve the issue. 172 * 173 * So, we must first read the RTC timestamp, 174 * then read the RTC alarm value, 175 * and then read a second RTC timestamp. 176 * 177 * If any fields of the second timestamp have changed 178 * when compared with the first timestamp, then we know 179 * our timestamp may be inconsistent with that used by 180 * the low-level rtc_read_alarm_internal() function. 181 * 182 * So, when the two timestamps disagree, we just loop and do 183 * the process again to get a fully consistent set of values. 184 * 185 * This could all instead be done in the lower level driver, 186 * but since more than one lower level RTC implementation needs it, 187 * then it‘s probably best best to do it here instead of there.. 188 */ 189 190 /* Get the "before" timestamp */ 191 err = rtc_read_time(rtc, &before); 192 if (err < 0) 193 return err; 194 do { 195 if (!first_time) 196 memcpy(&before, &now, sizeof(struct rtc_time)); 197 first_time = 0; 198 199 /* get the RTC alarm values, which may be incomplete */ 200 err = rtc_read_alarm_internal(rtc, alarm); 201 if (err) 202 return err; 203 if (!alarm->enabled) 204 return 0; 205 206 /* full-function RTCs won‘t have such missing fields */ 207 if (rtc_valid_tm(&alarm->time) == 0) 208 return 0; 209 210 /* get the "after" timestamp, to detect wrapped fields */ 211 err = rtc_read_time(rtc, &now); 212 if (err < 0) 213 return err; 214 215 /* note that tm_sec is a "don‘t care" value here: */ 216 } while ( before.tm_min != now.tm_min 217 || before.tm_hour != now.tm_hour 218 || before.tm_mon != now.tm_mon 219 || before.tm_year != now.tm_year); 220 221 /* Fill in the missing alarm fields using the timestamp; we 222 * know there‘s at least one since alarm->time is invalid. 223 */ 224 if (alarm->time.tm_sec == -1) 225 alarm->time.tm_sec = now.tm_sec; 226 if (alarm->time.tm_min == -1) 227 alarm->time.tm_min = now.tm_min; 228 if (alarm->time.tm_hour == -1) 229 alarm->time.tm_hour = now.tm_hour; 230 231 /* For simplicity, only support date rollover for now */ 232 if (alarm->time.tm_mday == -1) { 233 alarm->time.tm_mday = now.tm_mday; 234 missing = day; 235 } 236 if (alarm->time.tm_mon == -1) { 237 alarm->time.tm_mon = now.tm_mon; 238 if (missing == none) 239 missing = month; 240 } 241 if (alarm->time.tm_year == -1) { 242 alarm->time.tm_year = now.tm_year; 243 if (missing == none) 244 missing = year; 245 } 246 247 /* with luck, no rollover is needed */ 248 rtc_tm_to_time(&now, &t_now); 249 rtc_tm_to_time(&alarm->time, &t_alm); 250 if (t_now < t_alm) 251 goto done; 252 253 switch (missing) { 254 255 /* 24 hour rollover ... if it‘s now 10am Monday, an alarm that 256 * that will trigger at 5am will do so at 5am Tuesday, which 257 * could also be in the next month or year. This is a common 258 * case, especially for PCs. 259 */ 260 case day: 261 dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day"); 262 t_alm += 24 * 60 * 60; 263 rtc_time_to_tm(t_alm, &alarm->time); 264 break; 265 266 /* Month rollover ... if it‘s the 31th, an alarm on the 3rd will 267 * be next month. An alarm matching on the 30th, 29th, or 28th 268 * may end up in the month after that! Many newer PCs support 269 * this type of alarm. 270 */ 271 case month: 272 dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month"); 273 do { 274 if (alarm->time.tm_mon < 11) 275 alarm->time.tm_mon++; 276 else { 277 alarm->time.tm_mon = 0; 278 alarm->time.tm_year++; 279 } 280 days = rtc_month_days(alarm->time.tm_mon, 281 alarm->time.tm_year); 282 } while (days < alarm->time.tm_mday); 283 break; 284 285 /* Year rollover ... easy except for leap years! */ 286 case year: 287 dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year"); 288 do { 289 alarm->time.tm_year++; 290 } while (rtc_valid_tm(&alarm->time) != 0); 291 break; 292 293 default: 294 dev_warn(&rtc->dev, "alarm rollover not handled\n"); 295 } 296 297 done: 298 return 0; 299 } 300 EXPORT_SYMBOL_GPL(rtc_read_alarm); 301 302 int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 303 { 304 int err; 305 306 err = rtc_valid_tm(&alarm->time); 307 if (err != 0) 308 return err; 309 310 err = mutex_lock_interruptible(&rtc->ops_lock); 311 if (err) 312 return err; 313 314 if (!rtc->ops) 315 err = -ENODEV; 316 else if (!rtc->ops->set_alarm) 317 err = -EINVAL; 318 else 319 err = rtc->ops->set_alarm(rtc->dev.parent, alarm); 320 321 mutex_unlock(&rtc->ops_lock); 322 return err; 323 } 324 EXPORT_SYMBOL_GPL(rtc_set_alarm); 325 326 int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) 327 { 328 int err = mutex_lock_interruptible(&rtc->ops_lock); 329 if (err) 330 return err; 331 332 if (!rtc->ops) 333 err = -ENODEV; 334 else if (!rtc->ops->alarm_irq_enable) 335 err = -EINVAL; 336 else 337 err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled); 338 339 mutex_unlock(&rtc->ops_lock); 340 return err; 341 } 342 EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable); 343 344 int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) 345 { 346 int err = mutex_lock_interruptible(&rtc->ops_lock); 347 if (err) 348 return err; 349 350 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL 351 if (enabled == 0 && rtc->uie_irq_active) { 352 mutex_unlock(&rtc->ops_lock); 353 return rtc_dev_update_irq_enable_emul(rtc, enabled); 354 } 355 #endif 356 357 if (!rtc->ops) 358 err = -ENODEV; 359 else if (!rtc->ops->update_irq_enable) 360 err = -EINVAL; 361 else 362 err = rtc->ops->update_irq_enable(rtc->dev.parent, enabled); 363 364 mutex_unlock(&rtc->ops_lock); 365 366 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL 367 /* 368 * Enable emulation if the driver did not provide 369 * the update_irq_enable function pointer or if returned 370 * -EINVAL to signal that it has been configured without 371 * interrupts or that are not available at the moment. 372 */ 373 if (err == -EINVAL) 374 err = rtc_dev_update_irq_enable_emul(rtc, enabled); 375 #endif 376 return err; 377 } 378 EXPORT_SYMBOL_GPL(rtc_update_irq_enable); 379 380 /** 381 * rtc_update_irq - report RTC periodic, alarm, and/or update irqs 382 * @rtc: the rtc device 383 * @num: how many irqs are being reported (usually one) 384 * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF 385 * Context: any 386 */ 387 void rtc_update_irq(struct rtc_device *rtc, 388 unsigned long num, unsigned long events) 389 { 390 unsigned long flags; 391 392 spin_lock_irqsave(&rtc->irq_lock, flags); 393 rtc->irq_data = (rtc->irq_data + (num << 8)) | events; 394 spin_unlock_irqrestore(&rtc->irq_lock, flags); 395 396 spin_lock_irqsave(&rtc->irq_task_lock, flags); 397 if (rtc->irq_task) 398 rtc->irq_task->func(rtc->irq_task->private_data); 399 spin_unlock_irqrestore(&rtc->irq_task_lock, flags); 400 401 wake_up_interruptible(&rtc->irq_queue); 402 kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); 403 } 404 EXPORT_SYMBOL_GPL(rtc_update_irq); 405 406 static int __rtc_match(struct device *dev, void *data) 407 { 408 char *name = (char *)data; 409 410 if (strcmp(dev_name(dev), name) == 0) 411 return 1; 412 return 0; 413 } 414 415 struct rtc_device *rtc_class_open(char *name) 416 { 417 struct device *dev; 418 struct rtc_device *rtc = NULL; 419 420 dev = class_find_device(rtc_class, NULL, name, __rtc_match); 421 if (dev) 422 rtc = to_rtc_device(dev); 423 424 if (rtc) { 425 if (!try_module_get(rtc->owner)) { 426 put_device(dev); 427 rtc = NULL; 428 } 429 } 430 431 return rtc; 432 } 433 EXPORT_SYMBOL_GPL(rtc_class_open); 434 435 void rtc_class_close(struct rtc_device *rtc) 436 { 437 module_put(rtc->owner); 438 put_device(&rtc->dev); 439 } 440 EXPORT_SYMBOL_GPL(rtc_class_close); 441 442 int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task) 443 { 444 int retval = -EBUSY; 445 446 if (task == NULL || task->func == NULL) 447 return -EINVAL; 448 449 /* Cannot register while the char dev is in use */ 450 if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags)) 451 return -EBUSY; 452 453 spin_lock_irq(&rtc->irq_task_lock); 454 if (rtc->irq_task == NULL) { 455 rtc->irq_task = task; 456 retval = 0; 457 } 458 spin_unlock_irq(&rtc->irq_task_lock); 459 460 clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); 461 462 return retval; 463 } 464 EXPORT_SYMBOL_GPL(rtc_irq_register); 465 466 void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task) 467 { 468 spin_lock_irq(&rtc->irq_task_lock); 469 if (rtc->irq_task == task) 470 rtc->irq_task = NULL; 471 spin_unlock_irq(&rtc->irq_task_lock); 472 } 473 EXPORT_SYMBOL_GPL(rtc_irq_unregister); 474 475 /** 476 * rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs 477 * @rtc: the rtc device 478 * @task: currently registered with rtc_irq_register() 479 * @enabled: true to enable periodic IRQs 480 * Context: any 481 * 482 * Note that rtc_irq_set_freq() should previously have been used to 483 * specify the desired frequency of periodic IRQ task->func() callbacks. 484 */ 485 int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled) 486 { 487 int err = 0; 488 unsigned long flags; 489 490 if (rtc->ops->irq_set_state == NULL) 491 return -ENXIO; 492 493 spin_lock_irqsave(&rtc->irq_task_lock, flags); 494 if (rtc->irq_task != NULL && task == NULL) 495 err = -EBUSY; 496 if (rtc->irq_task != task) 497 err = -EACCES; 498 spin_unlock_irqrestore(&rtc->irq_task_lock, flags); 499 500 if (err == 0) 501 err = rtc->ops->irq_set_state(rtc->dev.parent, enabled); 502 503 return err; 504 } 505 EXPORT_SYMBOL_GPL(rtc_irq_set_state); 506 507 /** 508 * rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ 509 * @rtc: the rtc device 510 * @task: currently registered with rtc_irq_register() 511 * @freq: positive frequency with which task->func() will be called 512 * Context: any 513 * 514 * Note that rtc_irq_set_state() is used to enable or disable the 515 * periodic IRQs. 516 */ 517 int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) 518 { 519 int err = 0; 520 unsigned long flags; 521 522 if (rtc->ops->irq_set_freq == NULL) 523 return -ENXIO; 524 525 spin_lock_irqsave(&rtc->irq_task_lock, flags); 526 if (rtc->irq_task != NULL && task == NULL) 527 err = -EBUSY; 528 if (rtc->irq_task != task) 529 err = -EACCES; 530 spin_unlock_irqrestore(&rtc->irq_task_lock, flags); 531 532 if (err == 0) { 533 err = rtc->ops->irq_set_freq(rtc->dev.parent, freq); 534 if (err == 0) 535 rtc->irq_freq = freq; 536 } 537 return err; 538 } 539 EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
rtc-sysfs.c源代码:
1 /* 2 * RTC subsystem, sysfs interface 3 * 4 * Copyright (C) 2005 Tower Technologies 5 * Author: Alessandro Zummo <a.zummo@towertech.it> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 本文主要工作: 11 1.在init给rtc时钟增加闹钟属性 12 2.初始化一个struct device_attribute rtc_attrs[]属性结构体数组 13 3.在函数rtc_sysfs_add_device中增加闹钟属性文件 14 4.在函数rtc_sysfs_del_device中删除闹钟属性文件 15 */ 16 17 #include <linux/module.h> 18 #include <linux/rtc.h> 19 20 #include "rtc-core.h" 21 22 23 /* device attributes */ 24 25 /* 26 * NOTE: RTC times displayed in sysfs use the RTC‘s timezone. That‘s 27 * ideally UTC. However, PCs that also boot to MS-Windows normally use 28 * the local time and change to match daylight savings time. That affects 29 * attributes including date, time, since_epoch, and wakealarm. 30 */ 31 32 static ssize_t 33 rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr, 34 char *buf) 35 { 36 return sprintf(buf, "%s\n", to_rtc_device(dev)->name); 37 } 38 39 static ssize_t 40 rtc_sysfs_show_date(struct device *dev, struct device_attribute *attr, 41 char *buf) 42 { 43 ssize_t retval; 44 struct rtc_time tm; 45 46 retval = rtc_read_time(to_rtc_device(dev), &tm); 47 if (retval == 0) { 48 retval = sprintf(buf, "%04d-%02d-%02d\n", 49 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); 50 } 51 52 return retval; 53 } 54 55 static ssize_t 56 rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr, 57 char *buf) 58 { 59 ssize_t retval; 60 struct rtc_time tm; 61 62 retval = rtc_read_time(to_rtc_device(dev), &tm); 63 if (retval == 0) { 64 retval = sprintf(buf, "%02d:%02d:%02d\n", 65 tm.tm_hour, tm.tm_min, tm.tm_sec); 66 } 67 68 return retval; 69 } 70 71 static ssize_t 72 rtc_sysfs_show_since_epoch(struct device *dev, struct device_attribute *attr, 73 char *buf) 74 { 75 ssize_t retval; 76 struct rtc_time tm; 77 78 retval = rtc_read_time(to_rtc_device(dev), &tm); 79 if (retval == 0) { 80 unsigned long time; 81 rtc_tm_to_time(&tm, &time); 82 retval = sprintf(buf, "%lu\n", time); 83 } 84 85 return retval; 86 } 87 88 static ssize_t 89 rtc_sysfs_show_max_user_freq(struct device *dev, struct device_attribute *attr, 90 char *buf) 91 { 92 return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq); 93 } 94 95 static ssize_t 96 rtc_sysfs_set_max_user_freq(struct device *dev, struct device_attribute *attr, 97 const char *buf, size_t n) 98 { 99 struct rtc_device *rtc = to_rtc_device(dev); 100 unsigned long val = simple_strtoul(buf, NULL, 0); 101 102 if (val >= 4096 || val == 0) 103 return -EINVAL; 104 105 rtc->max_user_freq = (int)val; 106 107 return n; 108 } 109 110 static struct device_attribute rtc_attrs[] = { 111 __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL), 112 __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL), 113 __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL), 114 __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL), 115 __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq, 116 rtc_sysfs_set_max_user_freq), 117 { }, 118 }; 119 120 static ssize_t 121 rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr, 122 char *buf) 123 { 124 ssize_t retval; 125 unsigned long alarm; 126 struct rtc_wkalrm alm; 127 128 /* Don‘t show disabled alarms. For uniformity, RTC alarms are 129 * conceptually one-shot, even though some common RTCs (on PCs) 130 * don‘t actually work that way. 131 * 132 * NOTE: RTC implementations where the alarm doesn‘t match an 133 * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC 134 * alarms after they trigger, to ensure one-shot semantics. 135 */ 136 retval = rtc_read_alarm(to_rtc_device(dev), &alm); 137 if (retval == 0 && alm.enabled) { 138 rtc_tm_to_time(&alm.time, &alarm); 139 retval = sprintf(buf, "%lu\n", alarm); 140 } 141 142 return retval; 143 } 144 145 static ssize_t 146 rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, 147 const char *buf, size_t n) 148 { 149 ssize_t retval; 150 unsigned long now, alarm; 151 struct rtc_wkalrm alm; 152 struct rtc_device *rtc = to_rtc_device(dev); 153 char *buf_ptr; 154 int adjust = 0; 155 156 /* Only request alarms that trigger in the future. Disable them 157 * by writing another time, e.g. 0 meaning Jan 1 1970 UTC. 158 */ 159 retval = rtc_read_time(rtc, &alm.time); 160 if (retval < 0) 161 return retval; 162 rtc_tm_to_time(&alm.time, &now); 163 164 buf_ptr = (char *)buf; 165 if (*buf_ptr == ‘+‘) { 166 buf_ptr++; 167 adjust = 1; 168 } 169 alarm = simple_strtoul(buf_ptr, NULL, 0); 170 if (adjust) { 171 alarm += now; 172 } 173 if (alarm > now) { 174 /* Avoid accidentally clobbering active alarms; we can‘t 175 * entirely prevent that here, without even the minimal 176 * locking from the /dev/rtcN api. 177 */ 178 retval = rtc_read_alarm(rtc, &alm); 179 if (retval < 0) 180 return retval; 181 if (alm.enabled) 182 return -EBUSY; 183 184 alm.enabled = 1; 185 } else { 186 alm.enabled = 0; 187 188 /* Provide a valid future alarm time. Linux isn‘t EFI, 189 * this time won‘t be ignored when disabling the alarm. 190 */ 191 alarm = now + 300; 192 } 193 rtc_time_to_tm(alarm, &alm.time); 194 195 retval = rtc_set_alarm(rtc, &alm); 196 return (retval < 0) ? retval : n; 197 } 198 static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, 199 rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm); 200 201 202 /* The reason to trigger an alarm with no process watching it (via sysfs) 203 * is its side effect: waking from a system state like suspend-to-RAM or 204 * suspend-to-disk. So: no attribute unless that side effect is possible. 205 * (Userspace may disable that mechanism later.) 206 */ 207 static inline int rtc_does_wakealarm(struct rtc_device *rtc) 208 { 209 if (!device_can_wakeup(rtc->dev.parent)) 210 return 0; 211 return rtc->ops->set_alarm != NULL; 212 } 213 214 215 void rtc_sysfs_add_device(struct rtc_device *rtc) 216 { 217 int err; 218 219 /* not all RTCs support both alarms and wakeup */ 220 if (!rtc_does_wakealarm(rtc)) 221 return; 222 223 err = device_create_file(&rtc->dev, &dev_attr_wakealarm); 224 if (err) 225 dev_err(rtc->dev.parent, 226 "failed to create alarm attribute, %d\n", err); 227 } 228 229 void rtc_sysfs_del_device(struct rtc_device *rtc) 230 { 231 /* REVISIT did we add it successfully? */ 232 if (rtc_does_wakealarm(rtc)) 233 device_remove_file(&rtc->dev, &dev_attr_wakealarm); 234 } 235 236 void __init rtc_sysfs_init(struct class *rtc_class) 237 { 238 rtc_class->dev_attrs = rtc_attrs; //给rtc的类dev_attrs赋值rtc_attrs这个属性指针 239 }
rtc-proc.c源代码:
1 /* 2 * RTC subsystem, proc interface 3 * 4 * Copyright (C) 2005-06 Tower Technologies 5 * Author: Alessandro Zummo <a.zummo@towertech.it> 6 * 7 * based on arch/arm/common/rtctime.c 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13 14 #include <linux/module.h> 15 #include <linux/rtc.h> 16 #include <linux/proc_fs.h> 17 #include <linux/seq_file.h> 18 19 #include "rtc-core.h" 20 21 22 static int rtc_proc_show(struct seq_file *seq, void *offset) 23 { 24 int err; 25 struct rtc_device *rtc = seq->private; 26 const struct rtc_class_ops *ops = rtc->ops; 27 struct rtc_wkalrm alrm; 28 struct rtc_time tm; 29 30 err = rtc_read_time(rtc, &tm); 31 if (err == 0) { 32 seq_printf(seq, 33 "rtc_time\t: %02d:%02d:%02d\n" 34 "rtc_date\t: %04d-%02d-%02d\n", 35 tm.tm_hour, tm.tm_min, tm.tm_sec, 36 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); 37 } 38 39 err = rtc_read_alarm(rtc, &alrm); 40 if (err == 0) { 41 seq_printf(seq, "alrm_time\t: "); 42 if ((unsigned int)alrm.time.tm_hour <= 24) 43 seq_printf(seq, "%02d:", alrm.time.tm_hour); 44 else 45 seq_printf(seq, "**:"); 46 if ((unsigned int)alrm.time.tm_min <= 59) 47 seq_printf(seq, "%02d:", alrm.time.tm_min); 48 else 49 seq_printf(seq, "**:"); 50 if ((unsigned int)alrm.time.tm_sec <= 59) 51 seq_printf(seq, "%02d\n", alrm.time.tm_sec); 52 else 53 seq_printf(seq, "**\n"); 54 55 seq_printf(seq, "alrm_date\t: "); 56 if ((unsigned int)alrm.time.tm_year <= 200) 57 seq_printf(seq, "%04d-", alrm.time.tm_year + 1900); 58 else 59 seq_printf(seq, "****-"); 60 if ((unsigned int)alrm.time.tm_mon <= 11) 61 seq_printf(seq, "%02d-", alrm.time.tm_mon + 1); 62 else 63 seq_printf(seq, "**-"); 64 if (alrm.time.tm_mday && (unsigned int)alrm.time.tm_mday <= 31) 65 seq_printf(seq, "%02d\n", alrm.time.tm_mday); 66 else 67 seq_printf(seq, "**\n"); 68 seq_printf(seq, "alarm_IRQ\t: %s\n", 69 alrm.enabled ? "yes" : "no"); 70 seq_printf(seq, "alrm_pending\t: %s\n", 71 alrm.pending ? "yes" : "no"); 72 } 73 74 seq_printf(seq, "24hr\t\t: yes\n"); 75 76 if (ops->proc) 77 ops->proc(rtc->dev.parent, seq); 78 79 return 0; 80 } 81 82 static int rtc_proc_open(struct inode *inode, struct file *file) 83 { 84 struct rtc_device *rtc = PDE(inode)->data; 85 86 if (!try_module_get(THIS_MODULE)) 87 return -ENODEV; 88 89 return single_open(file, rtc_proc_show, rtc); 90 } 91 92 static int rtc_proc_release(struct inode *inode, struct file *file) 93 { 94 int res = single_release(inode, file); 95 module_put(THIS_MODULE); 96 return res; 97 } 98 99 static const struct file_operations rtc_proc_fops = { 100 .open = rtc_proc_open, 101 .read = seq_read, 102 .llseek = seq_lseek, 103 .release = rtc_proc_release, 104 }; 105 106 void rtc_proc_add_device(struct rtc_device *rtc) 107 { 108 if (rtc->id == 0) 109 proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc); 110 //proc_create_data完成创建文件节点的作用,并将文件的操作函数与节点联系起来 111 } 112 113 void rtc_proc_del_device(struct rtc_device *rtc) 114 { 115 if (rtc->id == 0) 116 remove_proc_entry("driver/rtc", NULL); 117 }
标签:
原文地址:http://www.cnblogs.com/lihaiyan/p/4318947.html