在Linux核心中增加新驅動模組
開發環境
開發板:A33-Vstar
開發板系統: Linux/arm 3.4.39 Kernel
Ubuntu版本:Ubuntu14.04
----------------------------------------------------
新增核心驅動,並可以通過make menuconfig配置。
核心完整路徑:~/A33-Vstar/dragonboard/linux-3.4
1. 構建測試模組:hello
1.1 在linux-3.4/drivers/下新建目錄hello
cd linux-3.4/drivers/
mkdir hello
1.2 在hello/下新建hello.c Makefile Kconfig三個檔案
hello.c:
#include <linux/module.h> //所有模組都需要的標頭檔案 #include <linux/init.h> // init&exit相關巨集 #include <linux/kernel.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("baoli"); MODULE_DESCRIPTION("hello world module"); static int __init hello_init(void) { printk(KERN_WARNING "hello world.\n"); return 0; } static void __exit hello_exit(void) { printk(KERN_WARNING "hello exit!\n"); } module_init(hello_init); module_exit(hello_exit);
Makefile:
obj-$(CONFIG_HELLO) += hello.o
Kconfig:
menu "HELLO TEST Driver "
comment "HELLO TEST Driver Config"
config HELLO
tristate "hello module test"
default m
help
This is the hello test driver --by baoli.
endmenu
1.3 修改上一級目錄的Kconfig和Makefile
進入linux-3.4/drivers/
1)編輯Makefile,在後面新增一行:
obj-$(CONFIG_HELLO) += hello/
2)編輯Kconfig,在後面新增一行:
source "drivers/hello/Kconfig"
注:某些核心版本需要同時在arch/arm/Kconfig中新增:source "drivers/hello/Kconfig"
2. make menuconfig配置
1)執行:make menuconfig ARCH=arm
2)選擇並進入:Device Drivers選項
可以看到新增 HELLO TEST Driver選項
3)進入 HELLO TEST Driver選項
可以選擇<m> <y> <n>,分別為編譯成核心模組、編譯進核心、不編譯。
3. 編譯
退出儲存後進入:cd ~/A33-Vstar/dragonboard/
執行:sudo ./build.sh 編譯核心
1)如果選擇編譯成模組<m>
編譯核心過程中,會有如下輸出:
LD drivers/hello/built-in.o
CC [M] drivers/hello/hello.o
CC drivers/hello/hello.mod.o
LD [M] drivers/hello/hello.ko
2)如果選擇編譯進核心<y>
編譯核心過程中,會有如下輸出:
CC drivers/hello/hello.o
LD drivers/hello/built-in.o
編譯完成後,drivers/hello/下新增hello.o和hello.ko,並且/linux-3.4/output/lib/modules/3.4.39/下也會有hello.ko。
4. 測試
4.1 編譯成核心模組
下載映象至A33開發板,使用minicom 超級終端和開發板連線。
cd /lib/modules/3.4.39
可看到hello.ko在此路徑下。
1)inmod hello.ko
dmesg | tail 顯示hello world.
2)rmmod hello
dmesg | tail 顯示hello exit!
注:hello.ko已經被打包進系統映象檔案,在路徑/lib/modules/3.4.39 下,所以下載安裝映象後不需要再重新拷貝映象至開發板。
4.2 編譯進核心
下載映象至A33開發板,系統啟動時在超級終端上顯示載入資訊:hello world.
5. 分析
5.1 source "drivers/hello/Kconfig"
在Kconfig中有類似語句:source "drivers/hello/Kconfig"
核心原始碼目錄樹中每一個Kconfig都會用source引入其所有子目錄下的Kconfig,從而保證了所有的Kconfig專案都被包含進menuconfig中。這個也說明了:如果你自己在linux核心中添加了一個資料夾,一定要在這個資料夾下建立一個Kconfig檔案,然後在這個資料夾的上一層目錄的Kconfig中source引入這個資料夾下的Kconfig檔案。
5.2 depends on
意思是本配置項依賴於另一個配置項。如果那個依賴的配置項為Y或者M,則本配置項才有意義;如果依賴的哪個配置項本身被設定為N,則本配置項根本沒有意義。depends項會導致make menuconfig的時候找不到一些配置項。所以在menuconfig中如果找不到一個選項,但是這個選項在Kconfig中卻是有的,則可能的原因就是這個配置項依賴的一個配置項是不成立的。depends依賴的配置項可以是多個,還可以有邏輯運算。這種時候只要依賴專案運算式子的結果為真則依賴就成立。
5.3 comment
用於定義一些幫助資訊,出現在介面的第一行。
5.4 menu/endmenu menuconfig
1)menu用於生成選單,其格式如下:
menu "Floating poing emulation"
config FPE_NWFPE
config FPE_NWFPE_XP
.............
endmenu
menu之後的Floating poing emulation是選單名,menu和endmenu間有很多config條目,在配置介面中如下所示:
Floating poing emulation--->
[] FPE_NWFPE
[] FPE_NWFPE_XP
2)menuconfig有點類似menu,但區別就在於menu後面多了一個config,這個menu是可以配置的,如下圖倒數第二行,前面比 menu型別多了一個<>,通過空格可以修改這個配置項的選中狀態。而且從格式上來看,也是有區別的。格式如init/Kconfig中1131行:
menuconfig MODULES
tristate "Enable loadable module support"config
if MODULES
xx
endif
也就是說,配置項是位於if和endif中。其中的部分就是MODULES子目錄顯示的內容。如果選中了MODULE,那麼if和endif中的內容可以顯示。如果沒有定義,就只能進入一個空目錄。
可以認為是menu和config的結合體,既在前面有選項,回車後也可以展開。
5.5 config
config是構成Kconfig的最基本單元,其中定義了配置項的詳細資訊。
1) 每個config選單項都要有型別定義: bool布林型別、 tristate三態(內建、模組、移除)、string字串、 hex十六進位制、 int整型。
例如:
config HELLO_MODULE
bool "hello test module"
bool 型別的只能選中或不選中,顯示為[ ];
tristate型別的選單項多了編譯成核心模組的選項,顯示為< > , 假如選擇編譯成核心模組,則會在.config中生成一個 CONFIG_HELLO_MODULE=m的配置,假如選擇內建,就是直接編譯成核心映象,就會在.config中生成一個 CONFIG_HELLO_MODULE=y的配置。
2) default:預設值
比如config型別是tristate,則預設值可以是y 、m、n。
5.6 Kconfig和.config檔案和Makefile三者的關聯
經過menuconfig配置之後儲存,就會在核心頂層目錄下生成.config檔案。
=y表示該配置將會被編譯進核心,=m表示該配置需要單獨編譯成模組。
核心頂層makefile會呼叫.config檔案,引用.config裡的配置,進而選擇性的編譯核心驅動模組。
配置項被配置成Y、N、M會影響“.config”檔案中的CONFIG_XXX變數的配置值。“.config”中的配置值(=y、=m、沒有)會影響最終的編譯連結過程。如果=y則會被編入(built-in),如果=m會被單獨連線成一個”.ko”模組,如果沒有則對應的程式碼不會被編譯。那麼這是怎麼實現的?都是通過makefile實現的。
如makefile中:obj-$(CONFIG_DM9000) += dm9000.o,
如果CONFIG_DM9000變數值為y,則obj += dm9000.o,因此dm9000.c會被編譯;如果CONFIG_DM9000變數未定義,則dm9000.c不會被編譯。如果CONFIG_DM9000變數的值為m則會被連線成“.ko”模組。
6. 問題及解決
make menuconfig 出現 endmenu in different file than menu
1)問題描述
新增一個驅動,然後在核心的頂層目錄進行如下操作
make menuconfig
出現瞭如下錯誤提示:
'endmenu' in different file than 'menu'
2)解決方案
在新增的驅動程式目錄中,在Kconfig檔案內
menu "Test Driver" config CONFIG_TEST bool "Test support" endmenu
注:在“endmenu” 下必須留一個空行。即 "endmenu" 後輸入一個回車,儲存。