Linux 内核中 RTC 驱动调用流程

Linux 内核将 RTC 设备抽象为 rtc_device 结构体,因此 RTC 设备驱动就是申请并初始化rtc_device,最后将 rtc_device 注册到 Linux 内核里面,这样 Linux 内核就有一个 RTC 设备了 。
当 rtc_class_ops 准备好以后需要将其注册到 Linux 内核中,这里我们可以使用rtc_device_register函数完成注册工作。此函数会申请一个rtc_device并且初始化这个rtc_device,最后向调用者返回这个 rtc_device,此函数原型如下:
1 2 3 4 5 6 7
| struct rtc_device *rtc_device_register(const char *name, struct device *dev, const struct rtc_class_ops *ops, struct module *owner)
void rtc_device_unregister(struct rtc_device *rtc)
|
RTC 设备的操作肯定是用一个操作集合(结构体 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| 104 struct rtc_device 105 { 106 struct device dev; 107 struct module *owner; 108 109 int id; 110 char name[RTC_DEVICE_NAME_SIZE]; 111 112 const struct rtc_class_ops *ops; 113 struct mutex ops_lock; 114 115 struct cdev char_dev; 116 unsigned long flags; 117 118 unsigned long irq_data; 119 spinlock_t irq_lock; 120 wait_queue_head_t irq_queue; 121 struct fasync_struct *async_queue; 122 123 struct rtc_task *irq_task; 124 spinlock_t irq_task_lock; 125 int irq_freq; 126 int max_user_freq; 127 128 struct timerqueue_head timerqueue; 129 struct rtc_timer aie_timer; 130 struct rtc_timer uie_rtctimer; 131 struct hrtimer pie_timer; 132 int pie_enabled; 133 struct work_struct irqwork; 134 135 int uie_unsupported; };
|
查看rtc_class_ops底层操作数集合,这个集合是最底层的 RTC 设备操作函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 71 struct rtc_class_ops { 72 int (*open)(struct device *); 73 void (*release)(struct device *); 74 int (*ioctl)(struct device *, unsigned int, unsigned long); 75 int (*read_time)(struct device *, struct rtc_time *); 76 int (*set_time)(struct device *, struct rtc_time *); 77 int (*read_alarm)(struct device *, struct rtc_wkalrm *); 78 int (*set_alarm)(struct device *, struct rtc_wkalrm *); 79 int (*proc)(struct device *, struct seq_file *); 80 int (*set_mmss64)(struct device *, time64_t secs); 81 int (*set_mmss)(struct device *, unsigned long secs); 82 int (*read_callback)(struct device *, int data); 83 int (*alarm_irq_enable)(struct device *, unsigned int enabled); 84 };
|
RTC 是字符设备(存在字符设备的 file_operations 函数操作集), Linux 内核提供了一个 RTC 通用字符设备驱动文件,文件名为 drivers/rtc/rtc-dev.c, rtcdev.c 文件提供了所有 RTC 设备共用的 file_operations 函数操作集
1 2 3 4 5 6 7 8 9 10 11
| 448 static const struct file_operations rtc_dev_fops = { 449 .owner = THIS_MODULE, 450 .llseek = no_llseek, 451 .read = rtc_dev_read, 452 .poll = rtc_dev_poll, 453 .unlocked_ioctl = rtc_dev_ioctl,
454 .open = rtc_dev_open, 455 .release = rtc_dev_release, 456 .fasync = rtc_dev_fasync, 457 };
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| 218 static long rtc_dev_ioctl(struct file *file, 219 unsigned int cmd, unsigned long arg) 220 { 221 int err = 0; 222 struct rtc_device *rtc = file->private_data; 223 const struct rtc_class_ops *ops = rtc->ops; 224 struct rtc_time tm; 225 struct rtc_wkalrm alarm; 226 void __user *uarg = (void __user *) arg; 227 228 err = mutex_lock_interruptible(&rtc->ops_lock); 229 if (err) 230 return err; ...... 269 switch (cmd) { ...... 333 case RTC_RD_TIME: 334 mutex_unlock(&rtc->ops_lock); 335 336 err = rtc_read_time(rtc, &tm); 337 if (err < 0) 338 return err; 339 340 if (copy_to_user(uarg, &tm, sizeof(tm))) 341 err = -EFAULT; 342 return err; 343 344 case RTC_SET_TIME: 345 mutex_unlock(&rtc->ops_lock); 346 347 if (copy_from_user(&tm, uarg, sizeof(tm))) 348 return -EFAULT; 349 350 return rtc_set_time(rtc, &tm); ...... 401 default: 402 403 if (ops->ioctl) { 404 err = ops->ioctl(rtc->dev.parent, cmd, arg); 405 if (err == -ENOIOCTLCMD) 406 err = -ENOTTY; 407 } else 408 err = -ENOTTY; 409 break; 410 } 411 412 done: 413 mutex_unlock(&rtc->ops_lock); 414 return err; 415 }
|
1、时间 RTC 查看
如果要查看时间的话输入“date”命令即可 。
2、设置 RTC 时间
RTC 时间设置也是使用的 date 命令,输入“date –help”命令即可查看 date 命令如何设置系统时间
1
| hwclock -w //将当前系统时间写入到 RTC 里面
|