驱动程序的作用
驱动程序是指与硬件设备和操作系统进行通信的软件。它的主要功能有以下几个方面:
-
提供硬件支持:驱动程序允许操作系统与硬件设备进行通信,以便正确地操作和控制硬件设备。它可以向操作系统提供有关硬件设备的各种信息,如设备类型、特性和功能。
-
硬件操作与控制:驱动程序可以向硬件设备发送指令和控制信号,以执行特定的操作和控制。例如,打印机驱动程序可以向打印机发送打印任务,并控制打印机的打印速度、纸张尺寸等。
-
设备管理:驱动程序可以提供设备管理功能,例如检测和识别新连接的设备,配置设备参数和设置选项,以及与其他设备进行协调和通信。
-
系统性能优化:驱动程序可以通过优化硬件设备的操作和与操作系统的通信来提高系统性能。它可以提供更高效的数据传输、更低的延迟和更好的资源利用。
-
错误处理和故障排除:驱动程序可以检测和处理硬件设备的错误和故障,并提供相应的错误处理和故障排除功能。它可以显示错误信息、尝试修复问题或建议用户采取适当的措施。
总的来说,驱动程序的功能是使操作系统能够与硬件设备进行有效的通信和控制,以便实现各种设备操作和管理功能,并提供系统性能优化和故障排除等服务。
驱动的框架
入口(安装):资源的申请
出口(卸载):资源的释放
许可证:GPL(Linux系统是开源的,写一个模块需要开源,所以需要写许可协议)
Linux内核许可规则 --- The Linux Kernel documentationhttps://docs.kernel.org/6.2/translations/zh_CN/process/license-rules.html
驱动代码框架
#include <linux/init.h>
#include <linux/module.h>
//申请资源
//static - 限定作用域,延长生命周期
//存储类型 数据类型 指定存放内存区域 函数名(形参)
static int __init hello_init(void)
{
return 0;
}
//释放资源
static void __exit hello_exit(void)
{
}
module_init(hello_init); //入口:申请资源 本质-回调一个自己写的函数
module_exit(hello_exit); //出口:释放资源
MODULE_LICENSE("GPL"); //许可证:公共许可协议(开源协议)
注释
module_init(X):入口;X为自己写的函数的函数名
它的作用是申请资源,也就是说,当你执行安装驱动的时候,他会立马执行你写的init函数中的相关功能。
module_exit(X):出口;X为自己写的函数的函数名
它的作用是释放资源,即当你卸载驱动的时候,会执行自己写的exit函数内的功能。
static: 限制作用域
因为在内核里面会有很多个驱动,驱动名字可能会有重复的,那么你在安装的时候就可能出现错误,他识别不到你到底是哪一个申请资源的函数,所有需要用static限制一下函数的作用域,让他只能在当前文件中使用。
__init :申请资源的区域
__exit :释放资源的区域
驱动Makefile的编写
驱动代码的编译需要依赖于内核,本质上你想把.c文件编译成一个驱动代码,使用的是make modules命令,但make modules是在内核的顶层路径下面去执行的,在下层文件中的.c想要编译就需要写一个自己的Makefile来编译生成驱动模块。
驱动Makefile代码
KERNELDIR = /home/linux/kernel/kernel-3.4.39 #写自己的开发板内核路径
#KERNELDIR = /lib/modules/$(shell uname -r)/build #PC机内核路径(尽量不要用,使用不当可能导致linux崩溃)
PWD = $(shell pwd) #驱动文件的路径
all:
make -C $(KERNELDIR) M=$(PWD) modules
.PHONY:clean
clean:
make -C $(KERNELDIR) M=$(PWD) clean
obj-m += hello.o
代码讲解
这段代码的作用是基于内核框架将驱动代码编译生成驱动模块,需要在内核的顶层目录下执行 make modules
-C:指定到哪个路径下执行这个命令(KERNELDIR中存放顶层路径)
M:赋值,要将哪个路径下的驱动文件编译生成驱动模块(使用shell pwd命令获取当前路径)
注:进入内核目录下执行make modules这条命令,如果不指定 M=$(PWD) 会把内核目录下的.c文件编译生成.ko
obj-m:功能是生成一个hello.ko 的模块
示例
代码:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
static int __init hello_init(void)
{
printk("hello world\n");
printk(KERN_CRIT "%s %s %d\n",__FILE__,__func__,__LINE__);
return 0;
}
static void __exit hello_exit(void)
{
printk("baibai le ninlei \n");
printk(KERN_CRIT "%s %s %d\n",__FILE__,__func__,__LINE__);
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
运行结果: