[Beijing Xunwei] i.MX6ULL Terminator Linux RTC Driver Experiment Introduction to Linux Kernel RTC Driver

In the Linux kernel, the RTC device driver is also a standard character device driver. The RTC device is operated in the application through functions such as open, close, read, write, and ioctl.
In the Linux kernel, the RTC device also has its own device structure rtc_device, so the process of the RTC device driver is the application and initialization of the rtc_device structure, and then the rtc_device structure is registered in the kernel. It can be seen that most devices are in such a process, but the structure and function of the device are different.
The rtc_device structure is defined in the include/linux/rtc.h file, and the content is as follows:

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; 
......
147 };

Although there are many member variables in the rtc_device structure, most of them don't need us to worry about. What we need to focus on is the ops member variable, which is a pointer variable of type rtc_class_ops. The rtc_class_ops structure is a collection of operation functions at the bottom of the RTC device, including functions such as reading and writing time. Therefore, the functions implemented in the rtc_class_ops structure are different in different RTC devices. The rtc_class_ops structure is defined in the include/linux/rtc.h file, and the content is as follows:

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 }; 

It can be seen from the member variables of the tc_class_ops structure that all functions are integrated. But it should be noted that these functions in rtc_class_ops are only the lowest RTC device operation functions, not the file_operations function operation set provided to the application layer. RTC is a character device, so there must be a file_operations function operation set for character devices. The Linux kernel provides a RTC universal character device driver file named drivers/rtc/rtc-dev.c. The rtc-dev.c file provides all The file_operations function operation set shared by RTC devices is as follows:

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 }; 

With the operation set of the standard character device, the application can realize the functions it needs through the functions in this structure. For example, to read and set the time, it will be realized through the rtc_dev_ioctl function. The rtc_dev_ioctl function will call the read_time, set_time and other functions in the rtc_class_ops structure to read and write to specific RTC devices. Let's take a brief look at the rtc_dev_ioctl function. The part of the function is as follows:

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 }

In line 333, RTC_RD_TIME is the time read command.
In line 336, if it is to read the time, call the rtc_read_time function to get the current RTC clock.
In the rtc_read_time function, rtc_read_time will call the __rtc_read_time function. The content of the __rtc_read_time function is as follows:

23 static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) 
24 {
    
     
25         int err; 
26       if (!rtc->ops) 
27             err = -ENODEV; 
28         else if (!rtc->ops->read_time) 
29             err = -EINVAL; 
30         else {
    
     
31             memset(tm, 0, sizeof(struct rtc_time)); 
32             err = rtc->ops->read_time(rtc->dev.parent, tm); 
33             if (err < 0) {
    
     
34                 dev_dbg(&rtc->dev, "read_time: fail to read: %d\n", 
35                     err); 
36                 return err; 
37             } 
38 
39             err = rtc_valid_tm(tm); 
40             if (err < 0) 
41                 dev_dbg(&rtc->dev, "read_time: rtc_time isn't valid\n"); 
42         } 
43         return err; 
44 }

On line 32, the __rtc_read_time function calls read_time in the rtc_class_ops structure to obtain the current time from the RTC device.
The other commands in the rtc_dev_ioctl function are similar, and the corresponding functions in the rtc_class_ops structure will eventually be called. Therefore, the calling process of the RTC driver in the Linux kernel is:
application (ioctl) -> kernel layer (rtc_dev_ioctl) -> device driver layer (rtc_class_ops)

rtc_device_register function: Register the rtc_device structure to the kernel. This function will apply for an rtc_device and initialize the rtc_device, and finally return the rtc_device to the caller. The function prototype is as follows:

struct rtc_device *rtc_device_register(const char *name, 
struct device *dev, 
const struct rtc_class_ops *ops, 
struct module *owner) 

name: The name of the device.
dev: device.
ops: RTC low-level driver function set.
owner: The owner of the drive module.
Return value: If the registration is successful, it will return rtc_device, if it is wrong, it will return a negative value.

rtc_device_unregister function: used the rtc_device structure of unregistered registration. The function prototype is as follows:
void rtc_device_unregister(struct rtc_device *rtc)

Insert picture description here

Guess you like

Origin blog.csdn.net/BeiJingXunWei/article/details/112358429