基本概念:
编程机制和策: “需要提供什么样的功能(机制)”和“如何使用这些功能(策略)”
编写驱动程序应注意:编写访问硬件的内核代码时,不要给用户强加任何策略。不过有时候还是需要实现一些策略,例如,某个数字IO驱动程序只提供以字节为单位访问硬件的方法,这样可以避免写额外代码来处理单个数据位的麻烦。
内核模块和应用程序: 理解module_init 和module_exit 。模块初始化的任务是为以后调用模块函数做预先准备; 模块退出函数是为了告诉内核“我要离开了不要再让我做任何事了”。 应用程序退出时可以不管资源的释放或者其他清理工作,但是,模块退出函数必须要仔细撤销初始化函数所做的一切,否则,在系统重新引导之前某些东西就会残留在系统中。
应用程序能够调用它并未定义的函数,这是因为链接过程能够解析外部引用从而使用适当的函数库。例如定义在libc中的printf函数就是这种可被调用的函数之一。然而,模块仅仅被链接到内核,因此它能调用的函数仅仅是由内核导出的那些函数,而不存在任何可链接的函数库。
因为没有任何函数库和模块链接,因此,源文件中不能包含通常的头文件,像
# To build modules outside of the kernel tree, we run "make"
# in the kernel source tree; the Makefile these then includes this
# Makefile once again.
# This conditional selects whether we are being included from the
# kernel Makefile or not.
ifeq ($(KERNELRELEASE),) #判断是否被上层makefile包含,区别在单独编译和与内核一起编译。
# Assume the source tree is where the running kernel was built
# You should set KERNELDIR in the environment if it's elsewhere
KERNELDIR ?= /lib/modules/$(shell uname -r)/build #指定内核路径,需要是目录中包含.config文件,即配置好的内核
# The current directory is passed to sub-makes as argument
PWD := $(shell pwd) #当前编译路径
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules #在当前路径生成模块
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install #编译好的模块会被拷贝到指定的路径中
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules modules_install clean
else
# called from kernel build system: just declare what our modules are
obj-m := hello.o
endif
makefile基础
赋值符号 “=” “:=” “?=” “+=”
= 是最基本的赋值
:= 是覆盖之前的值
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值 两个链接符之间用自动添加空格
关于 := 和 = 的区别看下面的例子
A=first
B:=$(A)add
A=final
all:
@echo $(B)
运行 make 结果显示 firstadd
A=first
B=$(A)add
A=final
all:
@echo $(B)
运行make显示 finaladd
总结:似乎 使用:=赋值的时候没有对后面的赋值语句进行检查,而使用 =的时候会受到后面语句的影响。
语句中@echo 和echo的区别是是否显示echo 。加@echo只显示输出结果不显示命令。echo会显示命令之后显示对应输出。
“ifdef”是条件关键字。语法是ifdef ;; else ; endif
ifdef只检验一个变量是否被赋值,它并不会去推导这个变量,并不会把变量扩展到当前位置。
“ifeq”与“ifdef”类似。“ifeq”语法是ifeq (;, ;),功能是比较参数“arg1”和“arg2”的值是否相同。
ifneq ($(KERNELRELEASE),)
module-objs:=hello.o #当有多个源文件时可以写成 hello1.o hello2.o
obj-m:=hello.o #有多个源文件时这个名字不能和上面的重复
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
endif
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules modules_install clean
学习中遇到问题:
1、printk输出数据没在终端显示
重新打开一个终端,在终端下输入
whlie true
do
sudo dmesg -c
sleep 1
done
这段程序会不停的读取当前系统日志并清空