筆者搞設備驅動有一個多月了,也看了一些程序,前段時間一直很亂,沒有辦法總結,所以一直沒有寫文章,昨日熱的睡不著,腦袋中卻分外清晰,於是整理思路,將一個多月的學習心得總結出來,一方面供廣大嵌入式Linux開發者參考,一方面穩固自己的知識。
我將分為5篇文章去總結,這是第一篇,因為Linux中的驅動都是以模塊的方式加載到內核中的,所以學習模塊編程必須成為第一步。
各種官方的介紹此處略過,我們先來看一個最簡單的模塊實例:helloworld!
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/module.h>
-
-
- MODULE_LICENSE("GPL"); //申明LICENSE,不寫編譯會有警告,所以還是寫了吧
-
- /*-----------------------------------------------------------------------------
- 函數名: hello_init
-
- 參數: void
- 返回值: <SPAN > </SPAN> int
- 描述: 模塊初始化函數,在安裝模塊時候執行
-
- *-----------------------------------------------------------------------------*/
- static int __init hello_init(void)
- {
- printk("hello world!--It is kernel speaking\n"); //類似於printf,是在內核中使用的打印函數
- return 0;
- }
-
- /*-----------------------------------------------------------------------------
- 函數名: hello_exit
-
- 參數: void
- 返回值: <SPAN > </SPAN>void
- 描述: 模塊退出函數,在安裝卸載時候執行
-
- *-----------------------------------------------------------------------------*/
-
- static void __exit hello_exit(void)
- {
- printk("Goodbye!Kernel\n");
- }
-
- module_init(hello_init);
- module_exit(hello_exit);
這個函數已經簡單的和helloworld一樣簡單清楚和可愛了,我只做幾點說明:
1.大家可以看到模塊函數沒有main函數,只有init函數,一般在模塊編譯好之後,會執行insmod命令,這是就會調用module_init函數中注冊的初始化函數,也就是hello_init函數!同樣在模塊用完之後,我們通常會執行rmmod以移除模塊,這時候就會調用module_exit中注冊的函數,也就是 hello_exit 函數。
2.__init和__exit,(注意是兩個下劃線)這個是兩個關鍵字,目的是告訴內核,在模塊init的時候開辟內存,在模塊退出的時候釋放內存,如果不加這兩個關鍵字,模塊卸載的時候就不會釋放內存,這就造成了內存的浪費。
Makefile:
有了程序,下面就要編譯程序了,模塊的編譯方法和編譯程序可不一樣,下面提供一個Makefile模板,這個時代已經不是從無到有的用手敲代碼了,而是在模板的基礎上改動,這樣才能提高效率:
- obj-m:=hello.o
-
- CURRENT_PATH :=$(shell pwd)
- #VERSION_NUM :=$(shell uname -r)
- #LINUX_PATH :=/usr/src/linux-headers-$(VERSION_NUM)
- LINUX_PATH :=~/by700/linux-2.6.30-atmel9260
-
- all :
- make -C $(LINUX_PATH) M=$(CURRENT_PATH) modules
-
- .PHONY :clean
- clean:
- rm -rf *.o *ko
我也做幾點說明:
1.object -m :=hello.o,是要編譯的模塊的目標文件對應於hello.c,所以需要根據具體情況修改
2.對於這個模板我們第二個要修改的地方就是內核目錄,大家看到我用#把兩句話隱藏掉了,這個方便開啟PC和目標 板之間的切換:
對於PC端,一般編譯好的內核源代碼就放在我#號隱掉的目錄下,只要#號去掉,同時把第二個LINUX_PATH隱掉,就可以直接使用這個Makefile文件,這個不難,主要是目標板上的模塊,我調試了兩天才調試通
對於目標板(筆者的是at91)的芯片,LINUX_PATH這個目錄就需要調整了,因為我們在PC機上編譯目標板的內核代碼由讀者自己選定,我這個暫時就選定在如代碼中的目錄下。
特別注意,這個目錄一定要和目標板燒寫的鏡像是一致的,否則會出現內核和模塊不匹配的錯誤,筆者就是被這個錯誤改了內核代碼,結果越來越多錯誤,最後請教高手才解決的
我在這裡用的交叉編譯環境是:arm-angstrom-linux-gnueabi-
所以在執行的make的時候,要執行如下:make ARCH=arm CROSS_COMPILE=arm-angstrom-linux-gnueabi-
結果如下:
- root@at91sam9260ek:/mnt/hello# insmod hello.ko
- hello world!--It is kernel speaking
- root@at91sam9260ek:/mnt/hello# lsmod
- Module Size Used by Not tainted
- hello 1120 0
- root@at91sam9260ek:/mnt/hello# rmmod hello
- Goodbye!Kernel
- root@at91sam9260ek:/mnt/hello# lsmod
- Module Size Used by Not tainted
- root@at91sam9260ek:/mnt/hello#
內核模塊可以加載的文件是.ko後綴名的!