从 2.4 到 2.6,Linux 内核在可装载模块机制、设备模型、一些核心 API 等方面发生较大改变,设备驱动研发人员面临着将驱动从 2.4 移植到 2.6 内核,或是使驱动同时支持2.4 和 2.6 内核的任务。站在设备驱动研发人员的角度,驱动由一个或几个外部可加载内核模块组成,本文针对 2.6 内核里模块机制的改变对编写设备驱动程式的影响,从内核模块的编译、装载时的版本检查、初始化和退出、模块使用计数、输出内核符号、命令行输入参数、许可证声明等方面比较了 2.4 和 2.6 内核的区别;并总结了使设备驱动同时支持 2.4 和 2.6 内核的一系列模板。
1.获取内核版本
当设备驱动需要同时支持不同版本内核时,在编译阶段,内核模块需要知道当前使用的内核源码的版本,从而使用相应的内核 API。2.4 和 2.6 内核下,源码头文档 linux/version.h 定义有:
LINUX_VERSION_CODE ― 内核版本的二进制表示,主、从、修订版本号各对应一个字节;
KERNEL_VERSION(major, minor, release) - 由主、从、修订版本号构造二进制版本号。
在同时支持2.4和2.6 内核的设备驱动程式中,经常能够看到以下代码段:
清单1:判断内核版本的代码段。
/*code in 2.6 kernel*/ /*code in 2.4 kernel */
2.内核模块机制的改变
2.1模块编译
从2.4到2.6,外部可装载内核模块的编译、连接过程连同Makefile的书写都发生了改变。
2.4内核中,模块的编译只需内核源码头文档;需要在包含linux/modules.h之前定义MODULE;编译、连接后生成的内核模块后缀为.o。
2.6内核中,模块的编译需要配置过的内核源码;编译、连接后生成的内核模块后缀为.ko;编译过程首先会到内核源码目录下,读取顶层的Makefile文档,然后再返回模块源码所在目录。
清单2:2.4 内核模块的Makefile模板
#Makefile2.4 KVER=$(shell uname -r) KDIR=/lib/modules/$(KVER)/build OBJS=mymodule.o CFLAGS=-DKERNEL -I$(KDIR)/include -DMODULE -DKERNEL_SYSCALLS -DEXPORT_SYMTAB -O2 -fomit--pointer -Wall -DMODVERSIONS -include $(KDIR)/include/linux/modversions.h
all: $(OBJS) mymodule.o: file1.o file2.o ld -r -o $@ $^ clean: rm -f *.o
在2.4 内核下,内核模块的Makefile和普通用户程式的Makefile在结构和语法上都相同,但是必须在CFLAGS中定义-DKERNEL- DMODULE,指定内核头文档目录-I$(KDIR)/include。有一点需注意,之所以在CFLAGS中定义变量,而不是在模块源码文档中定义,一方面这些预定义变量能够被模块中任何源码文档可见,另一方面等价于将这些预定义变量定义在源码文档的起始位置。在模块编译中,对于这些全局的预定义变量,一般在CFLAGS中定义。
清单3:2.6 内核模块的Makefile模板
# Makefile2.6 ifneq ($(KERNELRELEASE),) mymodule-objs := file1.o file2.o obj-m := mymodule.o else PWD := $(shell pwd) KVER ?= $(shell uname -r) KDIR := /lib/modules/$(KVER)/build all: $(MAKE) -C $(KDIR) M=$(PWD) clean: rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions endif
KERNELRELEASE是在内核源码的顶层Makefile中定义的一个变量,在第一次读取执行此Makefile时, KERNELRELEASE没有被定义,所以make将读取执行else之后的内容。假如make的目标是clean,直接执行clean操作,然后结束。当make的目标为all时,-C $(KDIR) 指明跳转到内核源码目录下读取那里的Makefile;M=$(PWD) 表明然后返回到当前目录继续读入、执行当前的Makefile。当从内核源码目录返回时,KERNELRELEASE已被被定义,kbuild也被启动去解析kbuild语法的语句,make将继续读取else之前的内容。else之前的内容为kbuild语法的语句, 指明模块源码中各文档的依赖关系,连同要生成的目标模块名。mymodule-objs := file1.o file2.o表示mymoudule.o 由file1.o和file2.o 连接生成。obj-m := mymodule.o表示编译连接后将生成mymodule.o模块。
补充一点,”$(MAKE) -C $(KDIR) M=$(PWD)”和”$(MAKE) -C $(KDIR) SUBDIRS =$(PWD)”的作用是等效的,后者是较老的使用方法。推荐使用M而不是SUBDIRS,前者更明确。
通过以上比较能够看到,从Makefile编写来看,在2.6内核下,内核模块编译不必定义复杂的CFLAGS,而且模块中各文档依赖关系的表示简洁清楚。
清单4: 可同时在2.4 和 2.6 内核下工作的Makefile
文章整理:西部数码--专业提供域名注册、虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!




