無論是vc還是vb,還是c#,還是jsp php等等語言,在學習他們之前總是先來乙個hello world的例子,這個好像成了我們程式入門的必經之路。所以在驅動程式的學習上,也離不開這個步驟。但是驅動程式的開發是執行在核心空間的,而應用程式是執行在使用者空間的,所以驅動程式的開發盒除錯和應用程式的開發都有很大的區別。對於這個hello world的程式我也化了不少時間才搞清楚。
驅動程式作為系統核心的一部分,它工作在核心態,而應用程式工作在使用者態。也就是說,不能直接通過指標,把使用者空間的資料位址傳遞給核心(因為mmu對映的位址根本不一樣)。要想在應用程式和驅動程式之間傳遞資料(指標),就需要經過轉換。把使用者態「看到」的空間位址轉換成核心態可訪問的位址。linux系統提供了一系列方便的函式實現這種轉換,如get_user、put_user、copy_from_user、copy_to_user等,它們自己負責訪問許可權的檢查,使用時,不需要關係更多的問題。
linux核心把驅動程式劃分為3種型別:字元裝置、塊裝置和網路裝置。字元裝置和塊裝置可以像檔案一樣被訪問。它們的主要區別不在於能否seek,而是在於系統對於這兩種型別裝置的管理方式。應用程式對於字元裝置的每乙個i/o操作,都會直接傳遞給系統核心對應的驅動程式;而應用程式對於塊裝置的操作,要經過系統的緩衝區管理,間接傳遞給驅動程式處理。塊裝置的這種管理方式是為儲存提供優化的;而字元裝置的管理方式是為操作提供優化的。至於網路裝置,它在linux系統中是一模擬較特殊的裝置它不像字元裝置或塊裝置那樣通過對應的裝置檔案節點去訪問,核心也不再通過read和write等呼叫去訪問網路裝置。linux的網路系統主要是基於bsd unix的套接字機制,在系統和驅動程式之間有專門的資料結構進行資料傳輸,系統支援對資料傳送和資料接收快取,提供流量控制機制,提供更多的協議支援。
在linux系統中,驅動程式都做成模組的形式,也就是module。簡單的說,乙個模組提供乙個功能,這些模組是可以按照需要隨時裝入核心空間和從核心空間解除安裝的。因此,核心模組是為了給核心動態增減功能而設計的,並不僅僅是限於驅動程式。
因為核心模組需要載入到核心空間,所以其程式的編寫與一般應用程式不同,在裡面再也找不到類似main()這樣的入口函式,下面對應函式相應的源**hello.c,分析乙個驅動模組的寫法。
#ifndef __kernel__
#define __kernel__
#endif
#ifndef module
#define module
#endif
#include //所有模組都需要的標頭檔案
#include
#include
#include // init和exit相關巨集
module_license("gpl");
int text_init(void)
void text_cleanup(void)
module_init(text_init); //註冊載入時執行的函式
module_exit(text_cleanup); //註冊解除安裝時執行的函式
乙個linux核心模組需包含模組初始化和模組解除安裝函式,前者在insmod的時候執行,後者在rmmod的時候執行。初始化與解除安裝函式必須在巨集module_init和module_exit使用前定義,否則會出現編譯錯誤。
程式中的module_license("gpl")用於宣告模組的許可證。
編譯:gcc -c -i /usr/src/linux-2.4/include/ hello.c
執行:insmod hello.o
終端上會顯示:
localhost kernel:hello world!
同時在/proc/modules裡面會看到相應的裝置資訊:
more /proc/modules
你會看到(或許後面的數值不一樣):
hello 844 0 (unused)
.......
解除安裝驅動程式:
rmmod hello
你將會在終端上面看到:
localhost kernel:goodbye world!
模組程式設計需要注意:
1.在gcc編譯選項中增加-c
2.在gcc編譯選項中定義兩個巨集:-dmodule -d__kerenl__
或直接在原始檔中定義這兩個巨集:
#define module
#define __kernel__
3.在原始檔中包括module.h檔案:
#i nclude
4.假定你現在執行的核心的原始碼目錄絕對路徑是mykernelsrcpath,在gcc編譯時增加選項:
-i $mykernelsrcpath/include (如-i /usr/src/linux/include)
5.某些時候用insmod -f能夠成功載入,但需謹慎使用。
6.如果看不到用printk列印的資訊,可以用dmesg命令看。
7.列印訊息受級別的限制,訊息級別可以通過printk設定,如:
printk("something"); /* 其中0 /proc/sys/kernel/printk
關於核心模組初始化(載入)函式
當使用者輸入命令「insmod 模組檔名」(或者其他方式)載入核心模組時,系統會檢測此模組能否被載入,如果能被載入,核心呼叫模組的初始化函式。在linux 2.4中,核心模組的初始化函式名為init_module()。但如果驅動程式需要編譯進核心,則初始化函式不能與核心的其他部分(包括其他核心模組)的函式同名。這樣,如果程式可能編譯到核心中時就比較麻煩。不過在這個標頭檔案中定義了巨集module_init(),用來遮蔽兩者的差別,事實上,使用這個巨集可以使驅動程式向上相容linux 2.6,而相容linux 2.0也比較方便。
關於核心模組清除(解除安裝)函式
當使用者輸入命令「rmmod 模組檔名」(或者其他方式)解除安裝核心模組時,此時,系統會檢測此模組是否能被解除安裝,核心將呼叫模組清除函式。在linux 2.4中,清除函式的函式名稱為cleanup_module()。但如果驅動程式需要編譯進核心,則初始化函式不能與核心的其他部分(包括其他核心模組)的函式同名。這樣,如果程式可能編譯到核心中時就比較麻煩。不過在這個標頭檔案中定義了巨集module_exit(),用來遮蔽兩者的差別。
Linux 驅動程式入門
驅動是具有入口和出口的一組方法的集合,這一組方法才是驅動的核心內容。對於字元裝置驅動程式,最核心的就是 file operation 結構,這個結構實際上是提供給虛擬檔案系統 vfs 的檔案介面,它的每乙個成員函式一般都對應乙個系統呼叫。使用者程序利用系統呼叫對裝置檔案進行諸如讀和寫操作時,系統呼叫...
Linux驅動程式入門 Hello World
2008 7 16 22 06 17 收藏 列印 投 票 74 中小 linux驅動程式入門 hello world ohy 20080716 1 引言 記得在學習vc 和c語言的時候,一開始都會以乙個hello world的例子作為演示,將學者逐漸引入殿堂,這個幾乎成了計算機程式語言學習必經的乙個...
Linux驅動程式入門 Hello World
1 引言 記得在學習vc 和c語言的時候,一開始都會以乙個hello world的例子作為演示,將學者逐漸引入殿堂,這個幾乎成了計算機程式語言學習必經的乙個入門之路。當然,在學習linux程式設計的時候也是這樣,下面的例子應該是再熟悉不過了 首先用vi編寫乙個c程式 vi hello.c inclu...