一個學習Linux設備驅動程序都會碰到的第一個例程:
de>#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_ALERT "Hello, Tekkaman Ninja !\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, Tekkaman Ninja !\n Love Linux !Love ARM ! Love KeKe !de>de>\nde>de>"de>de>de>de>);
}
module_init(hello_init);
module_exit(hello_exit);de>
我將其復制到我的工作目錄,並編寫了一個簡單的Makefile文件:
de>KERNELDIR = /home/tekkaman/working/SBC2440/linux-2.6.22.2
# The current directory is passed to sub-makes as argument
PWD := $(shell pwd)
INSTALLDIR = /home/tekkaman/working/rootfs/lib/modules
CROSS_COMPILE =/home/tekkaman/working/crosstool-gcc410-k26222/gcc-4.1.0-glibc-2.3.2/arm-9tdmi-linux-gnu/bin/arm-9tdmi-linux-gnu-
CC = $(CROSS_COMPILE)gcc
obj-m := hello.o
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
cp hello.ko $(INSTALLDIR)
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY: modules modules_install cleande>
說實話,以上是我參考了《Linux設備驅動程序(第3版)》的Makefile源碼修改得來的。我對Makefile不是很了解,是該好好學習學習了!
然後就是make modules 、 make modules_install 。
[root@Tekkaman-Ninja Helloworld]# make modules
make -C /home/tekkaman/working/SBC2440/linux-2.6.22.2 M=/home/tekkaman/working/Linuxdriver/Helloworld modules
make[1]: Entering directory `/home/tekkaman/working/SBC2440/linux-2.6.22.2'
CC [M] /home/tekkaman/working/Linuxdriver/Helloworld/hello.o
Building modules, stage 2.
MODPOST 1 modules
CC /home/tekkaman/working/Linuxdriver/Helloworld/hello.mod.o
LD [M] /home/tekkaman/working/Linuxdriver/Helloworld/hello.ko
make[1]: Leaving directory `/home/tekkaman/working/SBC2440/linux-2.6.22.2'
[root@Tekkaman-Ninja Helloworld]# make modules_install
cp hello.ko /home/tekkaman/working/rootfs/lib/modules
[root@Tekkaman-Ninja Helloworld]#
在我的開發板上的操作:
[Tekkaman2440@SBC2440V4]#cd /lib/modules/
[Tekkaman2440@SBC2440V4]#ls
cs89x0.ko hello.ko p80211.ko prism2_usb.ko
[Tekkaman2440@SBC2440V4]#insmod hello.ko
Hello, Tekkaman Ninja !
[Tekkaman2440@SBC2440V4]#lsmod
Module Size Used by Not tainted
hello 1376 0
[Tekkaman2440@SBC2440V4]#rmmod hello
Goodbye, Tekkaman Ninja !
Love Linux !Love ARM ! Love KeKe !
[Tekkaman2440@SBC2440V4]#lsmod
Module Size Used by Not tainted
[Tekkaman2440@SBC2440V4]#
--------------------------------------------------------------------------------
學習心得:
(1)驅動模塊運行在內核空間,運行時不能依賴於任何函數庫和模塊連接,所以在寫驅動時所調用的函數只能是作為內核一部分的函數。
(2)驅動模塊和應用程序的一個重要不同是:應用程序退出時可不管資源釋放或者其他的清除工作,但模塊的退出函數必須仔細撤銷初始化函數所作的一切,否則,在系統重新引導之前某些東西就會殘留在系統中。
(3)處理器的多種工作模式(級別)其實就是為了操作系統的用戶空間和內核空間設計的。在Unix類的操作系統中只用到了兩個級別:最高和最低級別。
(4)要十分注意驅動程序的並發處理。
(5)內核API中具有雙下劃線(_ _)的函數,通常是接口的底層組件,應慎用。
(6)內核代碼不能實現浮點書運算。
(7)Makefile文件分析:
de>obj-m := hello.o 代表了我們要構造的模塊名為hell.ko,make 會在該目錄下自動找到hell.c文件進行編譯。如果 de>de>hello.o是由其他的源文件生成(比如file1.c和de>de>file2.cde>de>)的,則在下面加上(注意紅色字體的對應關系):
de>de>de>de style="color: rgb(255, 1, 2);">hellode>de>-objs := file1.o file2.o ......de>
de> $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
其中 de>de>-C $(KERNELDIR) 指定了內核源代碼的位置,其中保存有內核的頂層makefile文件。
de>de>M=$(PWD) de>de>指定了模塊源代碼的位置
de>de>modules目標指向obj-m變量中設定的模塊。
de>(8)insmod使用公共內核符號表來解析模塊中未定義的符號。公共內核符號表中包含了所有的全局內核項(即函數和變量的地址),這是實現模塊化驅動程序所必須的。
(9)Linux使用模塊層疊技術,我們可以將模塊劃分為多個層,通過簡化每個層可縮短開發周期。如果一個模塊需要向其他模塊到處符號,則使用下面的宏:
de>EXPORT_SYMBOL(name);
EXPORT_SYMBOL_GPL(name);de>
符號必須在模塊文件的全局變量部分導出,因為這兩個宏將被擴展為一個特殊變量的聲明,而該變量必須是全局的。
(10)所有模塊代碼中都包含一下兩個頭文件:
de>#include <linux/init.h>
#include <linux/module.h> de>
(11)所有模塊代碼都應該指定所使用的許可證: