程序框架说明(和之前的LED驱动进行对比)
这个程序的框架与之前学习的第二个驱动程序(控制LED)的框架基本一致,第二个驱动程序的链接如下:
https://blog.youkuaiyun.com/wenhao_ir/article/details/144973219
所以如果前两这个LED驱动程序的框架掌握得很清楚了,这里驱动程序的框架就没啥好说的了。
不过二者还是有点不同,具体的不同如下:
①在控制LED的驱动程序中,下层的代码虽然被独立为一个文件,但并没有作为一个单独的模块,即没有初始函数和退出函数,而是和驱动的上层代码文件一起被编译成一个模块。本文中的下层驱动代码和上层驱动代码就是各自形成一个模块,虽然我觉得这样并不方便(相当于加载一个驱动还得加载两个模块,增加了操作的复杂性),但是既然官方提供的代码框架是这样,我就不改了,以后我就根据实际需要去选择是用LED驱动中的那种只有一个模块的结构还是这篇博文中被分别编译成两个模块的结构吧。
②在控制LED的驱动程序中,设备文件的建立是在驱动程序框架的上层文件的模块初始化函数中完成的,关键代码如下:
函数get_board_led_opr
是在底层文件中定义的函数,相关关键代码如下:
static struct led_operations board_demo_led_opr = {
.num = 1,
.init = board_demo_led_init,
.ctl = board_demo_led_ctl,
.close = board_demo_led_close,
};
struct led_operations *get_board_led_opr(void)
{
return &board_demo_led_opr;
}
而本文中的驱动程序的框架中,设备文件的创建和销毁是在驱动程序的上层文件中被封装成了两个函数,代码如下:
void register_button_operations(struct button_operations *opr)
{
int i;
p_button_opr = opr;
for (i = 0; i < opr->count; i++)
{
device_create(button_class, NULL, MKDEV(major, i), NULL, "swh_button%d", i);
}
}
void unregister_button_operations(void)
{
int i;
for (i = 0; i < p_button_opr->count; i++)
{
device_destroy(button_class, MKDEV(major, i));
}
}
底层代码在初始化和退出时调用这两个在上层文件中的函数进行设备文件的创建和销毁,相关代码如下:
int board_imx6ull_button_drv_init(void)
{
register_button_operations(&my_buttons_ops);
return 0;
}
void board_imx6ull_button_drv_exit(void)
{
unregister_button_operations();
}
可见,如果这两个文件被分别编译成两个模块,这里的加载顺序应该是要先加载上层的模块,再加载下层的模块。因为下层的模块需要调用上层模块的函数。
完整源代码
自定义头文件button_drv.h
的内容
#ifndef _BUTTON_DRV_H
#define _BUTTON_DRV_H
struct button_operations {
int count;
void (*init) (int which);
int (*read) (int which);
void (*close) (int which);
};
void register_button_operations(struct button_operations *opr);
void unregister_button_operations(void);
#endif
驱动程序上层源代码button_drv.c
的内容
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/fs.h>
#include <linux/signal.h>
#include <linux/mutex.h>
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/poll.h>
#include <linux/capi.h>
#include <linux/kernelcapi.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
#include "button_drv.h"
static int major = 0;
static struct button_operations *p_button_opr;
static struct class *button_class;
static int button_open (struct inode *inode, struct file *file)
{
int minor = iminor(inode);
p_button_opr->init(minor);
return 0;
}
static ssize_t button_read (struct file *file, char __user *buf, size_t size, loff_t *off)
{
unsigned int minor = iminor(file_inode(file