驱动基础介绍
1 驱动加载成功以后会在 /dev 目录下生成一个相应文件夹,通过对文件夹下的内容进行调用
2 include/linux/fs.h 中的 file_operations 结构体定义了 linux 内核驱动操作函数集合
owner 拥有该结构体的模块的指针,一般设置为 THIS_MODULE
llseek 函数用于修改文件当前的读写位置
read 函数用于读设备文件
write 函数用于写设备文件
poll 轮询函数,用于查询设备是否可以进行非阻塞的读写
unlocked_ioctl 函数提供对于设备的控制功能,与应用程序中的 ioctl 函数对应
compat_ioctl 与 Unlocked_ioctl 区别在于在 64 位系统上,32 位的应用程序调用将会使用此函数,而在 32 位系统调用 unlocked_ioctl
mmap 用于将设备的内存映射到进程空间(用户空间),一般帧缓冲设备会使用此函数,例如 LCD 驱动的显存,可以避免来回复制
open 函数打开设备文件
release 函数释放(关闭) 设备文件,与应用程序中的 close 函数对应
fasync 函数用于刷新待处理的数据,用于将缓冲区中的数据刷新到磁盘中
aio_fasync 函数是异步处理
驱动模块接口
1 出入口函数
insmod xxx.ko 加载驱动
rmmod xxx.ko 卸载驱动
lsmod 已加载驱动的列表
modprobe -r xx.ko 一键卸载驱动模块所依赖的其它模块
在文件中需要声明
//驱动入口
static int __init xx_init(void)
{
return 0;
}
//驱动出口
static void __exit xxx_exit(void)
{
}
//向 linux 声明出入口函数
module_init(xxx_init);
module_exit(xxx_exit);
2 字符设备注册与注销
static inline int register_chrdev(unsigned int major, const char *name, const struct file_operations *fops)
static inline void unregister_chrdev(unsigned int major, const char *name)
// major 主设备号,Linux 下每一个设备都又一个设备号
// name 设备名字
// fops 结构体 file_operations 类型指针,指向设备的操作函数集合变量
ll 例程
static struct file_operations test_fops;
static int __int xxx_init(void)
{
int retvalue = 0;
retvalue = register_chrdev(200, "chrtest", &test_fops);
if (retvalue < 0) {
//字符设备注册失败,自行处理
}
return 0;
}
static void __exit xxx_exit(void)
{
unregister_chrdev(200, "chrtest");
}
module_init(xxx_init):
module_exit(xxx_init);
注意: cat /proc/devices 要确保设备号没有被使用
3 实现具体操作函数
3.1 开 / 关
3.2 读 / 写
//打开设备
static int chrtest_open(struct inode *inode, struct file *filp) {
//具体实现功能
return 0;
}
//从设备读取
static ssize_t chrtest_read(struct file *filp, char __user *buf,
size_t cnt, loff_t *offt) {
//具体功能
retunr 0;
}
//向从设备写数据
static ssize_t chrtest_write(struct file *filp,
const char __user *buf,
size_t cnt, loff_t *offt)
{
//具体功能
return 0;
}
//关闭 / 释放设备
static int chrteat_release(struct inode *inode, struct file *filp)
{
//具体功能
retunr 0;
}
//核心
static struct file_operations test_fops = {
.owner = THIS_MODULE,
.open = chrtest_open,
.read = chrtest_read,
.write = chrtest_write,
.release = chrtest_release,
};
static int __init xxx_init(void)
{
int retvalue = 0;
retvalue = register_chrdev(200, "chrtest", &test_fops);
if (retvalue < 0) {
//注册失败自行处理
}
return 0;
}
static void __exit xxx_exit(void)
{
unregister_chrdev(200, "chrtest");
}
module_init(xxx_init);
module_exit(xxx_exit);
MODULE_LICENSE("GPL"); //证书必须加
MODULE_AUTHOR("xxxxx"); //作者 非必须