Linux 设备驱动练习---模块 加载卸载

看来一段时间的 LDD3 感觉看是看得懂,理论性比较强,还是得自己动手实践啊.

今天自己动手实践了下,错误百出,遇到各种问题,在此作下记录,大家一起学习.

很简单的一个加载模块的驱动--Hello.

虚拟机下的Linux系统下:

开始我在虚拟机下的Linux系统下实践.

下面是代码--hello.c:

#include 
#include 
MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
	printk(KERN_ALERT "Hello, world\n");
	return 0;
}

static void hello_exit(void)
{
	printk(KERN_ALERT "Goodbye, cruel world\n");
}

module_init(hello_init);
module_exit(hello_exit);

直接gcc编译的话,会报错,找不到头文件.

在我们系统自带的内核代码树下 cd /usr/src/kernels/2.6.18-53.el5-i686/有这些代码的头文件,

/lib/modules/`uname -r`/build
这个目录下同样有这些文件.

我们可以采用下面的命令查找:

[root@localhost 2.6.18-53.el5-i686]# ls include/linux/ |grep init.h
init.h
[root@localhost 2.6.18-53.el5-i686]# 
最好就是采用Makefie了.

下面是 Makefile 文件,这 Makefile 文件和 hello.c 必须在同一目录下.

obj-m:=hello.o
KDIR:=/lib/modules/`uname -r`/build
PWD:=$(shell pwd)
default:
	make -C $(KDIR) M=$(PWD) modules
clean:
	rm -rf *.o .*.cmd *.ko *.mod.c .tmp_versions *.symvers

`uname -r`  就是获取当前系统的内核版本,避免我们在加载模块的时候出现不匹配的问题.

注意 `uname -r` 两边的标识符是 键盘上 1  左边的字符,不是单引号,或者我们可以用 $(shell uname -r)  来代替.

执行 make 命令:

[root@localhost drivers]# make
make -C /lib/modules/`uname -r`/build M=/home/yikai/drivers modules
make[1]: Entering directory `/usr/src/kernels/2.6.18-53.el5-i686'
  CC [M]  /home/yikai/drivers/hello.o
  Building modules, stage 2.
  MODPOST
  CC      /home/yikai/drivers/hello.mod.o
  LD [M]  /home/yikai/drivers/hello.ko
make[1]: Leaving directory `/usr/src/kernels/2.6.18-53.el5-i686'
[root@localhost drivers]# ls
hello.c  hello.ko  hello.mod.c  hello.mod.o  hello.o  Makefile  Module.symvers
[root@localhost drivers]# 
编译完成,产生了 hello.ko 文件.

可是执行  insmod hello.ko 命令,终端下没有打印信息.

[root@localhost drivers]# insmod hello.ko 
[root@localhost drivers]# 
其实我们可以在/var/log/messages 中看到打印的信息
 cat /var/log/messages
Mar 26 14:07:15 localhost kernel: Hello, world
[root@localhost drivers]# 

或者我们还可以使用 dmesg 来查看:

[root@localhost drivers]# dmesg |tail -3
Hello, world
Goodbye, cruel world
Hello, world
[root@localhost drivers]# 

看不到打印信息是是由于 KERN_ALERT优先级不够高,这里需要修改为:KERN_EMERG,再次编译,加载模块即可以看到结果

需要注意的是只有超级用户才能加载和卸载模块.

另外,如果有多个文件,则按下列方式编写Makefile文件(file1.c、file2.c):

obj -m := modulename.o
module-objs := file1.o file2.o


TQ2440 ARM9 Linux系统下:

下面是在在我的 TQ2440 ARM9开发板上加载模块:

hello.c程序不用改变.

按照上面的 Makefile 例子 编写 Makefie.

obj-m := hello.o

KERNELDIR = /opt/EmbedSky/linux-2.6.30.4
PWD := $(shell pwd)
INSTALLDIR = /home/yikai/modules
CROSS_COMPILE    = arm-linux-
CC    = $(CROSS_COMPILE)gcc

.PHONY:modules modules_install clean

modules:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

modules_install:
	cp hello.ko $(INSTALLDIR)
clean:
	rm -rf *.o *.order .depend .*.cmd *.ko *.mod.c .tmp_versions *.symvers
最后 make ,得到我们需要的 hello.ko 文件:

[root@localhost arm]# ls
hello.c  hello.ko  hello.mod.c  hello.mod.o  hello.o  Makefile  modules.order  Module.symvers
[root@localhost arm]# 
再就是拷贝到开发板运行了.


遇到的些问题:

下面说下我遇到的些问题:

1. 在 ARM9 的 Makefie 时候 得注释掉 CROSS_COMPILE 和 CC ,貌似在内核源代码下已经指定了,注释的话就不会报错,

但是偶然重启机器,发现上面的不注释也可以编译通过,我估计是我虚拟机下的 Linux  系统那时候抽风 找不到 指定的 交叉工具链.

2. 再就是 我在写头文件的时候,在头文件的 < > 尖括号内侧的两边 加了 空格,提示找不到头文件.

#include 
#include 
变成了:
#include < linux/init.h >
#include < linux/module.h >
报错:

/home/yikai/arm/hello.c:1:25: error:  linux/init.h : No such file or directory
/home/yikai/arm/hello.c:2:27: error:  linux/module.h : No such file or directory

所以得注意这一坏习惯.






你可能感兴趣的:(Linux,设备驱动程序学习,Linux,模块)