linux 驱动模块开发初体验

老谢的自留地 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 程序文件来。需要注意的是,因为第一个驱动程序需要依赖第二个驱动程序中开放的接口,因此必须先加载第二个驱动程序。


相关推荐