Mini2440 是基于S3C2440(2410工业版) 的Arm9平台,实验平台已经移植了Linux,目前正打算添加RF24L01接口驱动程序。
首先建立Helloworld驱动程序,作为驱动开发的模版,记录如下:
一、建立编译环境:
mini2440开发环境
编译器 : arm-linux-gcc 3.4.1
linux内核版本 : 2.6.32.2
解压并记录内核源码树 位置例:/opt/FriendlyARM/mini2440/linux-2.6.32.2
二、编写驱动程序文件:
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_ALERT "Hello module\n");
return 0;
}
static int hello_exit(void)
{
printk(KERN_ALERT "Goodby module\n");
return 0;
}
module_init(hello_init);
module_exit(hello_exit);
上述实现了在加载时打印相关语句功能,KERN_ALERT 表示了优先级为KERN_ALERT级别,较低级别的printk可能出现在终端无显示的情况。
三、编写Makefile
这里所配置的makefile模板文件如下:
#Mini2440 General Makefile for SSDUT_MCU_LAB
#Auth: sigmax6
#2011 03 01
CC = arm-linux-gcc #name of platform compiler
KDIR ?= /opt/FriendlyARM/mini2440/linux-2.6.32.2 #platform linux source dir
PWD := $(shell pwd)
obj-m := hello.o #obj-m means hello.ko , and it depends on hello.o
default:
$(MAKE) -C $(KDIR) M=$(PWD) modules #make
.PHONY: clean
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean #clean
rm -rf *.o *.ko .*.cmd *.mod.*
实际上,对于一个驱动模块来说,在有了hello.c之后,只要一句规则就可以生成目标模块
obj-m := hello.o
熟悉的 make , 但是对 2.6 内核建立系统不熟悉的读者, 可能奇怪这个 makefile 如何工作. 毕竟上面的这一行不是一个传统的 makefile 的样子. 答案, 当然, 是内核建立系统处理了余下的工作. 上面的安排
( 它利用了由 GNU make 提供的扩展语法 )表明有一个模块要从目标文件 hello.o 建立. 在从目标文件建立后结果模块命名为 hello.ko.
反之, 如果你有一个模块名为 module.ko, 是来自 2 个源文件( 姑且称之为, file1.c 和 file2.c ), 正确的书
写应当是:obj-m := module.o
module-objs := file1.o file2.o
对于一个象上面展示的要工作的 makefile, 它必须在更大的内核建立系统的上下文被调用. 如果你
的内核源码数位于, 假设, 你的 ~/kernel-2.6 目录, 用来建立你的模块的 make 命令( 在包含模块源码
和 makefile 的目录下键入 )会是:
make -C ~/kernel-2.6 M=`pwd` modules
这个命令开始是改变它的目录到用 -C 选项提供的目录下( 就是说, 你的内核源码目录 ). 它在那里
会发现内核的顶层 makefile. 这个 M= 选项使 makefile 在试图建立模块目标前, 回到你的模块源码目
录. 这个目标, 依次地, 是指在 obj-m 变量中发现的模块列表, 在我们的例子里设成了 module.o.
键入前面的 make 命令一会儿之后就会感觉烦, 所以内核开发者就开发了一种 makefile 方式, 使得生
活容易些对于那些在内核树之外建立模块的人. 这个窍门是如下书写你的 makefile:
# If KERNELRELEASE is defined, we've been invoked from the # kernel build system and can use its language. ifneq ($(KERNELRELEASE),) obj-m := hello.o # Otherwise we were called directly from the command # line; invoke the kernel build system. else KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules endif再一次, 我们看到了扩展的 GNU make 语法在起作用. 这个 makefile 在一次典型的建立中要被读 2次. 当从命令行中调用这个 makefile , 它注意到 KERNELRELEASE 变量没有设置. 它利用这样一个事实来定位内核源码目录, 即已安装模块目录中的符号连接指回内核建立树. 如果你实际上没有运行你在为其而建立的内核, 你可以在命令行提供一个 KERNELDIR= 选项, 设置 KERNELDIR 环境变量, 或者重写 makefile 中设置 KERNELDIR 的那一行. 一旦发现内核源码树, makefile 调用 default: 目标, 来运行第 2 个 make 命令( 在 makefile 里参数化成 $(MAKE))象前面描述过的一样来调用内核建立系统. 在第 2 次读, makefile 设置 obj-m, 并且内核的 makefile 文件完成实际的建立模块工作.这种建立模块的机制你可能感觉笨拙模糊. 一旦你习惯了它, 但是, 你很可能会欣赏这种已经编排进内核建立系统的能力. 注意, 上面的不是一个完整的 makefile; 一个真正的 makefile 包含通常的目标类型来清除不要的文件, 安装模块等等.
” —— 《Linux设备驱动程序 中文第三版》
在当前目录下 使用make命令生成.ko模块文件
按照上文的讲解,其中还会生成很多中间文件,格式为*.cmd *.mod.* 等 这些文件是系统将你的代码转化而来的。最终产品是.ko文件,也就是驱动模块。
Helloworld模块没有实际的操作,所以并不需要测试程序。一般情况下驱动程序需要通过测试程序验证其功能。
将.ko文件下载到目标系统中,使用:
#insmod hello.ko
就可以看到 “Hello module” 出现在终端上。
同理
#rmmod hello (这里没有后缀名,因为调用的是模块名称)
"会显示 “Goodbye module”
原文: http://sigmav.net/2011/03/mini2440-helloworld%e9%a9%b1%e5%8a%a8/