內核源碼樹的目錄下都有兩個文檔Kconfig和Makefile。分布到各目錄的Kconfig構成了一個分布式的內核配置數據庫,每個Kconfig分別描述了所屬目錄源文檔相關的內核配置菜單。在內核配置makemenuconfig時,從Kconfig中讀出菜單,用戶選擇后保存到.config的內核配置文檔中。在內核編譯時,主Makefile調用這個.config,就知道了用戶的選擇。
上面的內容說明了,Kconfig就是對應著內核的配置菜單。假如要想添加新的驅動到內核的源碼中,能夠修改Kconfig,這樣就能夠選擇這個驅動,假如想使這個驅動被編譯,要修改Makefile。所以,添加新的驅動時需要修改的文檔有兩種(注意不只是兩個)*Kconfig,*Makefile
.config是make menuconfig【配置后生成的一個配置文件,也就是說可以拷貝一個別人配置好的.config來使用,內核中不同開發板也自帶了一些配置文件在arch/arm/config/目錄下面有很多配置文件可以選擇和自己單板相似。
第一種方法:
利用內核自身的Makefile特性來編譯我們的驅動程序,下面由一個簡單的hello.c驅動程序來說明。
在/drivers/char/目錄下寫hello.c ?修改Makefile,Kconfig
hello.c內容:
~~~
#include <linux/init.h> ? ? ? ? ? /* 初始化模塊所用到的頭文件 */
#include <linux/module.h> ? /* KERN_ALERT用到的 頭文件*/
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);
MODULE_LICENSE("Dual BSD/GPL"); ? /* 通用的協議 */
MODULE_AUTHOR("wangluoren"); ? ? /* 作者 */
MODULE_DESCRIPTION("A simple hello world module"); ? /* 程序描述 */
MODULE_ALIAS("A simplest module"); ? ? ? ? ? ? /* 別名 */
Kconfig內容:
config HELLO ? ? ? ? ? /* Makefile中編譯可變選項中宏的名字,作用就是定義一個可以選擇的變量 */
tristate "Hello Driver added by Dong" ? ? ? ?/* make menuconfig 菜單界面顯示的信息,tristate 提供Y M N三種選項?*/
default n ? ? ? ? ? /* 菜單選項默認為N */
help
?? test for adding driver to menuconfig. ? ? /* 一些幫助信息,寫不寫沒有關系 */
MakeFile內容:?
obj-$(CONFIG_HELLO) += hello.o ? ? /*CONFIG_HELLO我們在Kconfig中區定義它,我們用 HELLO ,hello是文件名字*/
~~~
到此為止我們就寫好了這個hello的驅動程序,然后我們可以make menuconfig 在
~~~
Device Drivers ?--->
?Character devices ?--->
<?> Hello Driver added by Dong ??/* 可以按空格選擇Y M N ,來分別 編譯進內核,模塊,不編譯*/
~~~
如果是直接編譯進內核就可以執行make uImage ,如果是編譯成模塊就執行make modules.
上面我們采用的是靜態編譯方法看起來是那么的麻煩,當我們寫驅動程序的時候如果采用這種方法的話那就夠折騰了,我估計你調試一個驅動程序你都得折騰大半天,這種方法是我們確定我們驅動程序沒有問題后在編譯進內核。
第二種方法:
一般我們采用動態編譯來寫驅動程序,具體方法如下:
還是拿hello.c程序為例:
hello.c內容:
~~~
#include <linux/init.h> ? ? ? ? ? /* 初始化模塊所用到的頭文件 */
#include <linux/module.h> ? /*?KERN_ALERT用到的 頭文件*/
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);
MODULE_LICENSE("Dual BSD/GPL"); ? /* 通用的協議 */
MODULE_AUTHOR("wangluoren"); ? ? /* 作者 */
MODULE_DESCRIPTION("A simple hello world module"); ? /* 程序描述 */
MODULE_ALIAS("A simplest module"); ? ? ? ? ? ? /* 別名 */
~~~
Makefile文件編寫如下:(和hello.c放在同一層目錄就OK)
~~~
KERN_DIR = /home/book/workspace/kernel/linux-3.4.2_jz2440 ? /* 虛擬機kernel的路徑,每個人不一樣 */
all:
? ? ? ? make -C $(KERN_DIR) M=`pwd` modules ? /* -C 表示進入后面KERN_DIR這個目錄把當前路徑的hello.c編譯成模塊*/
clean:
? ? ? ? make -C $(KERN_DIR) M=`pwd` modules clean ?/* 一些清除工作,清除中間生成的中間文件 */
? ? ? ? rm -rf modules.order
obj-m ? += hello.o ? ? ? ? ? ? ? ? ? ? ? ?/* 編譯,這里要注意這個hello是你要編譯的程序的文件名字 */?
~~~
上面兩種方法編譯完成后都會生成一個hello.ko的文件,我們把這個文件復制到開發板的目錄下面,執行如下命令insmod hello.ko ?就會打印:Hello, world
rmmod hello 就會打印 ?Goodbye, cruel world ?(這個是一一對應的,加載一次只能卸載一次,不能重復加載)
補充一:
動態加載補充一點:如果我要用一個Makefile同時編譯多個文件該怎么辦呢?(這個文件的一個函數在另外一個文件當中定義,我們可以采取如下方法)方法如下:
有來個驅動文件:hello.c ?hello1.c
我們可以把上面Makefile中obj-m +=hello.o改成如下命令就可以了
~~~
obj-m :=led.o
module-objs :=hello.o hello1.o ? /* 這時候生成的 驅動文件就是led.ko */
~~~
補充二:
如果同時又兩個驅動程序都需要編譯(兩者之間沒有任何聯系的,就是共同用kernel來編譯自己的驅動)
比如有兩個文件:`hello1.c ?hello2.c?`
我們可以在同一個Makefile中這樣來編寫:
~~~
obj-m+=hello1.o
obj-m+= hello2.o ?
~~~ ?(注意這個:=已經變成+=,這兩者的區別這里就不說明了)
補充三:
上面靜態編譯驅動我們采用的是在/drivers/char目錄下面添加一個文件,我們也可以在/drivers目錄下面添加一個文件夾,下面我們講講具體的怎么來實現。
我們在/drivers目錄下面添加一個hello的文件夾,里面創建一個hello.c,Kconfig,Makefile,這個三個文件和靜態編譯添加一個文件是完全相同的,主要是更改的是/drivers目錄下的Makefile和Kconfig文件。
Makefile中添加如下命令:
~~~
obj-$(CONFIG_HELLO) += hello/ ? ? ? ?/* CONFIG_HELLO這個宏定義在hello目錄里面的Kconfig中,‘/’表示進入這個目錄,調用子目錄Makefile來編譯子目錄中的文件?*/
Kconfig添加如下命令:
source "drivers/hello/Kconfig" ? ? /* 把Kconfig導出到子菜單界面 */
~~~
然后執行make modules ? 就在drivers/hello目錄下面生成了一個hello.ko的文件
現在這個驅動編譯的全部用法基本講解完畢,有了這些知識你自己都可以去分析內核的結構,從頂層Makefile開始分析,子目錄下的Makefile想對簡單的多,頂層Makefile是比較難的,頂層Makefile講解在這篇文章中,[請點擊這里!](http://blog.csdn.net/qq_21792169/article/details/50448639)
上面講解了一些基礎的知識,這些知識對一個驅動開發成員已經足夠了,如果你是工作在內核空間,那你就應該深入分析這些結構的原理,比如怎么添加遞歸創建子目錄,通配符,正則表達式等,你都需要去深入了解。希望我這篇文章能給驅動開發者帶來幫助。