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,//RTC 底层驱动函数集
struct module *owner) //驱动模块拥有者
//注册成功的话就返回 rtc_device,错误的话会返回一个负值。
void rtc_device_unregister(struct rtc_device *rtc)
//rtc:要删除的 rtc_device。返回值: 无。

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; /* ID */
110 char name[RTC_DEVICE_NAME_SIZE]; /* 名字 */
111
112 const struct rtc_class_ops *ops; /* RTC 设备底层操作函数 比较重要*/
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; /* sub second exp, so needs hrtimer */
132 int pie_enabled;
133 struct work_struct irqwork;
134 /* Some hardware can't support UIE mode */
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,/* rtc_class_ops 中的 read_time、
set_time 等函数来对具体 RTC 设备的读写操作。*/
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 /* Finally try the driver's ioctl interface */
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 里面