虽然现在已经在Linux底层驱动工程师的路上走了一年多,但是很多细节应为工作中没有遇到过,所以也没有去了解过详细的原因,但是最近发现一些基础还是很重要的,所以现在开始弥补一些东西,经可能的详细的去说明一些东西。
后续也打算将这一些系列更新下去
这篇文章是我之前学习的一个文章,后续的将会在这个基础上进行
上次的Makefile文件也在这里补充说明一下:
一、Makefile文件说明
代码:
KEVN := $(shell uname -r)
PWD := $(shell pwd)
KERN_DIR := /lib/modules/$(KEVN)/build
obj-m := hello.o
all:
make -C $(KERN_DIR) M=$(PWD) modules
clean:
make -C $(KERN_DIR) M=$(PWD) clean
上面就是一个简单的
KEVN := $(shell uname -r)
KEVN代表的是内核版本,这只是一个名字,随便你改。
$(shell uname -r) 就相当于你的 shell下执行了 一次 uname -r 的命令,执行这个命令就是查看你当前PC的内核版本
PWD := $(shell pwd)
PWD代表就是当前的代码路径,一个名字和 KEVN一样的意思
$(shell pwd) 这个就是一个执行命令而已
KERN_DIR := /lib/modules/$(KEVN)/build
KERN_DIR 代表的是你内核编译需要的目录,同样的名字这些可以随便修改。
/lib/modules/$(KEVN)/build
后面就是ubuntu系统中的一些库了 ,其中包含我们的头文件。
不然没办法编译过。
二、驱动框架
先看驱动源码
#include <linux/module.h>
#include <linux/init.h>
static int hello_init(void) {
printk(KERN_DEBUG "hello world\n");
return 0;
}
static void hello_exit(void) {
printk(KERN_DEBUG"goodbye my world\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE ("GPL");
MODULE_AUTHOR ("XHH");
MODULE_DESCRIPTION ("A test module");
驱动的入口函数
module_init(hello_init);
// 这里去调用的hello_init函数
驱动的出口函数
module_exit(hello_exit);
驱动的出口函数
需要注意的是,入口函数是Int类型有返回值
出口函数是void类型,是没有返回值的
再android的内核中,即使我们的入口函数和出口函数名字是一样的,我们也可以成功的编译,原因是内核做好了工作,每个驱动module_init的时候,都会有自己的属性,属于是独一无二,即使的你名字是重名的,也不影响,就好像你会遇到一个和你重名的人,但是你遇不到一个和你同一个身份证号的人。
但是为了规范,我们也一般不会去报驱动名字弄成一样的。
三、编译多个ko模块
KEVN := $(shell uname -r)
PWD := $(shell pwd)
KERN_DIR := /lib/modules/$(KEVN)/build
obj-m := hello.o
all:
make -C $(KERN_DIR) M=$(PWD) modules
clean:
make -C $(KERN_DIR) M=$(PWD) clean
这里其实是有问题的,问题就在
obj-m := hello.o
这里,没错,单独编译一个驱动是没有问题的。但是如果你继续添加一个驱动呢
比如我再添加一个驱动,
KEVN := $(shell uname -r)
PWD := $(shell pwd)
KERN_DIR := /lib/modules/$(KEVN)/build
obj-m := hello.o
obj-m := hello_world.o
all:
make -C $(KERN_DIR) M=$(PWD) modules
clean:
make -C $(KERN_DIR) M=$(PWD) clean
你会发现只编译了hello_wrold这个模块,你的hell.ko模块没有编译出来。
当你互换两个顺序的时候
obj-m := hello_world.o
obj-m := hello.o
你会发现只编译了hello.ko,宾没有编译hello_world的模块。这是为啥呢,因为
:= 这个符号的原因。
如果我们需要编译多个ko那么就需要将这个:= 改为 +=
因为 := 是覆盖之前的值 += 是继续添加值。
可以理解为我 := 这个算法我之看最后一次的,之前赋予的值会被覆盖掉,所以我们在Makefile里面添加多少个驱动,只有最后一个会生效。
所以我们要编译多个驱动只需要将 := 改为 += 就可以了
一般来说这是内核给你做好了的,
内核里面都是用的+= 所以一般我们也不会注意这个问题,这里提出来说一下。