老谢的自留地 2020-02-09
2020-02-09
关键字:
在嵌入式 Linux 开发中,驱动程序通常都是用 C语言 来编写的,并经编译后生成为目标文件,即 ‘.o‘ 文件。随后又可在编译系统时以两种形式打包成系统镜像文件:
1、uImage
即内核的二进制文件。这种形式是直接将内核驱动程序打包进系统文件中。这种形式的驱动程序将会在内核加载时运行,即随系统启动而运行。这种形式的驱动预置在一定程度上会影响系统的开机耗时。
2、ko 文件
即 kernel object,这种形式是将驱动程序以独立的模块文件存在于系统中。这种形式的驱动程序灵活度高,可以在系统启动完成后慢慢加载运行,也可以直接在系统运行期卸载驱动。ko 形式的驱动在开发时的前提是系统内核已编译成功。
嵌入式 Linux 的驱动程序编写是有规范的,通常可以遵照如下几个步骤来编写:
1、编写头文件
#include <linux/init.h>
#include <linux/module.h>
2、驱动模块装载和卸载函数入口声明
module_init(cus_drv_init);
module_exit(cus_drv_exit);
3、实现模块装载和卸载的函数入口
static int __init cus_drv_init(void)
{
//一般在这个函数里做申请系统资源操作。
return 0;
}
static void __exit cus_drv_exit(void)
{
//一般在这里释放申请到的系统资源操作。
}
以上两个函数入口函数中的 __init 与 __exit 可以填写也可以不填写。
4、GPL声明
MODULE_LICENSE("GPL");
ko 形式的驱动程序在加载时可以传参。例如:insmod hello.ko myname="chorm" myvalue=27
在驱动代码中,处理这种参数的的函数声明为:
module_param(name, type, perm);
参数1 表示要传递的参数的名称,如 myname, myvalue。
参数2 表示参数的类型,如charp, int。
参数3 表示文件的权限,如0666。每个驱动程序在加载后会在 /sys/modules 下创建文件,这里指定的权限就是用于这个创建文件用的。
嵌入式 Linux 驱动模块程序的开发允许像普通C程序那样编译出“驱动支援库”来供其它 ko 程序调用。这种驱动支援库也是以 ko 存在的,它与普通的驱动程序的不同之处在于不需要实现驱动入口函数,即不需要上面四个步骤中的第2、第3步。同时在驱动支援库中将需要开放出去的接口函数以 EXPORT_SYMBOL(function_name); 的形式声明。以下是一个普通 ko 驱动调用支援ko库的示例源码:
#include <linux/init.h> #include <linux/module.h> #include "mymath.h" static int __init hello_init() { printk("module init.\n"); printk("add result:%d\n", my_add(122, 6)); return 0; } static void __exit hello_exit() { printk("module exit.\n"); } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE("GPL");
mymath.h 是支援ko库的接口头文件。
#include <linux/init.h> #include <linux/module.h> int my_add(int a, int b) { return a + b; } EXPORT_SIMBOL(my_add); MODULE_LICENSE("GPL");
以上两个源码文件将会编译出两个 ko 程序文件来。需要注意的是,因为第一个驱动程序需要依赖第二个驱动程序中开放的接口,因此必须先加载第二个驱动程序。