標籤:
Android深度探索(卷1)HAL與驅動開發學習筆記(6)
第六章 第一個Linux驅動程式 統計單詞個數
Linux系統將每一個驅動都映射成一個檔案.這些檔案稱為裝置檔案或驅動檔案,都儲存在/dev目錄中。這種設計理念使得與Linux驅動進行互動就像與普通檔案進行互動一樣容易。雖然C語言裡沒有事件的概念,但卻有與事件類別似的概念,這就是回調(c a l l b a c k)函數。因此,編寫Lin u x驅動最重要的一步就是編寫陰調函數,否則與裝置檔案互動的資料將無法得到處理。
6.1編寫Linux驅動的步驟
- 建立Linux驅動骨架
- 註冊和登出裝置檔案
- 指定與驅動相關的資訊
- 指定回呼函數
- 編寫商務邏輯
- 編寫makefile 檔案
- 編譯Linux驅動程式
- 安裝和卸載Linux驅動
* 上面8步中的前5步是關於如何編寫Lin u x驅動程J字的,通過後3步可以使L i n u x驅動正常工作。
6.2 編寫L i n u驅動程式前的準備工作
本例的L i n u x驅動原始碼並未與li n u x核心原始碼放在一起,而是單獨放在一個目錄。* 首先使用下面的命令建立存放Li n u x驅動程式的目錄。
# mkdir -p/root/drivers/ch06/word_count
# cd /root/drivers/ch0 6/word_count
* 然後,使用下面的命令建立驅動原始碼檔案(word count.c)
# echo ’’>word_count.c
最後編寫一個M a k e f i l e檔案,
# echo ‘obj-m := word_count.o ’ > Makefile
6.3 編寫L i n u x驅動程式的骨架(初始化和退出驅動)
代碼中使用了p r i n t k函數。該函數用於輸出日誌資訊printk函數與p r i n t f函數的用法類似。linux系統將記憶體分為了使用者空間和核心空間,這兩個空間的程式不能直接存取。p r i n t f函數運行在使用者空間,p r i n t k函數運行在核空間。因此,屬於核心程式的L i n u x驅動是不能直接存取p r i n t f函數的。運行在這兩塊記憶體中的程式之間互動的-方法很多。其中,裝置檔案就是一種主要的互動方式,如果使用者空間的程式要訪問核心空間,只要做一個可以訪問核心空間的驅動程式,然後使用者空間的程式通過裝置檔案與驅動程式進行互動即可.那麼,如何在linux驅動程式中動態分配記憶體空間呢?解決類似的問題也很簡單。既然L i n u x驅動無法直接調用運行在使用者空間的函數,那麼,在L i n u x核心中就必須要提供替代品。可以進入<Li n u x核心原始碼>/i n c l u d e目錄,該目錄的各個子目錄中…包含了大量的C語言標頭檔,這些標頭檔中定義資源就是運行在使用者空間的程式的替代品。
6.4. 安裝查看和卸載Linux驅動
* 安裝Linux驅動
# ismod word_count.ko
* 查看word_count 是否安裝成功
# lsmod I grep word_count
* 卸載Linux驅動
# remmod word_count
* 查看Linux驅動的輸出資訊
# dmesg | grep word_cound | tail -n 2
6.5 指定與驅動相關的資訊
一般需要為L i n u x驅動程式,指定如下資訊。
模組使用MODULE_AUTHOR宏指定。
模組描述:使用MODULE_DESCRIPTION宏指定。
模組別名:使用MODULE_ALIAS宏指定。
開源協議:使用MODULE_LICENSE宏指定。
代碼如下(一般放在word_count.c最後):
MODULE_AUTHOR(“lining”);
MODULE_DESCRIPTION(“statistics of word count .”);
MODULE_ALIAS(“word count module .”);
MODULE_LICENSE(“GPL”);
6.6 註冊和登出裝置檔案
為w o r d_c o u n t驅動建立一個裝置檔案,該裝置檔案的名稱是w o r d c o unt,位於/d e v目錄中。裝置檔案與普通檔案不同,不能使用I O函數建立,需要使用m i s c_r egister函數建立裝置檔案,使用m i s c_d e r e g i s t e r函數登出(移除〉裝置檔案。
* 編寫中的注意事項
1.設備檔案由主裝置號和次裝置號描述。而使用m i s c _ r e g i s t e r函數只能設定次裝置號。主裝置號統一設為10。主裝置號為1 0的裝置是L i n µ x系統中擁有共同特性的簡單字元裝置。這類裝置稱為m i s c裝置。
2. miscdevice.name變數的值就是裝置檔案的名稱。在本例中裝置檔案名稱為w o r d c o u n t .
3. 如果成功註冊了裝置檔案,m i s c _ _ r e g i s t e r函數返回非0的整數,如果註冊裝置檔案失敗返回0。
4. w o r d_c o u n t . c中的所有函數、變量都聲明成了s t a t i c。C語言中用s t a t i c聲明函數、變數等資源,系統會將這些函數和變數單獨放在記憶體的某一個地區,直到程式完全退出,否則這些資源不會被釋放, L i n u x驅動一旦裝載,除非手動卸載或關機,驅動會一直駐留記憶體,因此這些函數和變數資源會一直在記憶體中。也就是說多次調用這些資源不用再進行壓棧,出棧操作了,有利於提高驅動的運行效率。
6.7 指定回呼函數
- w o r d _ c o u n t_r e a d和word_c o u n t_w r i t e函數的參數基本相同,只有第2個參數b u f稍微有差異。word _count _r e a d.函數的b u f參數類型是c h a r*,而w o r d _count _w r i t e函數的b u f參數類型是co n s t char*;這就意味著w o r d _count _w r i t e函數中的b u f參數值無法修改。Word_count_read函數中的b u f參數表示從裝置檔案讀出的資料,也就是說b u f中的資料都可能自裝置檔案讀出,至於可以讀出多少資料,取決於w o r d _count _r e a d.函數的傳回值。
- 由於核心空間的程式不能直接存取使用者空間中的資料,因此需要在.w o r d_c o u n t -r e a d和 word _c o unt_w r i t e函數中分別使用copy_to_user和c o p y _ from_user函數將資料從核心空間複製到使用者空間戒從使用者空間複製到核心空間。
6.8測試Linux驅動的多種方法
1.使用Ubuntu Linux測試Linux驅動
2.A n d r o i d模擬器上通過原生(Native )C程式測試L i n u x驅動
* 用於Andr o i d類比的g o l d f i s h核心預設不允許動態裝載L i n u x驅動模組,因此需要在編譯L i n u x核心之前執行如下命令配置L i n u x核心。
# cd kernel goldfish
# make menuconfig
* 執行上面的命令後,按空格鍵將第二頂“Enable loadable module s u p p ort”選中前面是(*),然後按斷行符號鍵選入子功能表,選中前3項,否則L i n u x驅動模快仍然無法安裝和卸載。當退出設定菜單時保持設定。最後重新編譯Linux核心,成功編譯核心後, A n d r o i d模擬器可以使用新產生的zImage核心檔案動態裝載L i n u x驅動模組。
*在執行build.h指令檔完成對w o r ld_c o u n t驅動的編譯、上傳和安裝的工作,然後進入A n d r o i d模擬器的終端,使用e c h o和d mesg命令可以演出w o r d _ c o u n t驅動和查看測試時結果。
* 為了使編譯步驟儘可能簡單使用Android設 置 編 譯 參 數 , 並 使 用 make命令進行編譯。首先在root/driver/ch06/word_count目錄中建立一個A n d r o i d . m k檔案,並輸入如下的內容。
LOCAL PATH:= $ (call my -dir)
include $(CLEAR VARS)
#指定要編譯的原始碼檔案
LOCAL _SRC _FILES := test _word_count .c
#指定模組名,也是編譯後產生的可執行檔名
LOCAL_MODULE:= test_word_cunt
LOCAL _MODU LE _T AGS:= optional
include $(BUILD_EXECUTABLE)
A r i dro i d . m k檔案中有如下兩個地方需要說明一下.
LO C AL _MODULE_TAGS.
表示當前工程(A n d roi d .mk檔案所在的目錄)在什麼模式下編譯。如果設為optional,表示不考慮模式,也就是說,在任何膜式下都會編譯。該變數可以設定的值有us er、use r d e b u g、e ng、 o p t i o n a l其中eng是預設值。
include $(BUILD_EXEC UT ABLE) .
BUILD _EXECUTABLE表示建立可執行檔檔案。可執行檔路徑是<A n d r o i d原始碼目錄〉
3.使用Android ADK設定Linux驅動
4.使用JAVA代碼直接操作裝置檔案來測試Linux驅動
5.使用S3C6410開發板測試Linux驅動
6.將驅動編譯進Linux核心進行測試
Android深度探索(卷1)HAL與驅動開發學習筆記(6)