開發可統計單詞個數的Android驅動程式(1)開發可統計單詞個數的Android驅動程式(2)

來源:互聯網
上載者:User

    Android本質上是基於Linux核心的系統,也就是說Android就是一種Linux作業系統。只不過大多數時候都會運行在ARM架構的裝置上,例如,Android手機、平板等。Android驅動實際上就是Linux驅動,只是這裡使用Android深度探索(卷1):安裝C/C++交叉編譯環境 介 紹的交叉編譯器將Linux驅動編譯成了ARM架構的,所以驅動可以安裝在Android模擬器、Android手機(需要root)或平板上(這些裝置 都要使用給予ARM架構的CPU),當然,使用傳統的GCC也可以編譯成X86架構的驅動(並不需要修改代碼),這樣也可以在Ubuntu Linux上安裝Linux驅動。

      本文及後面幾篇文章主要介紹如何利用Android模擬器和S3C6410開發板開發給予ARM架構的Linux驅動,當然,測試的環境是 Android,而不是我們通常使用的Ubuntu Linux等X86架構的系統。最後會介紹通過多種方式測試這個驅動,測試方法包括命令列、NDK、Android程式(Java代碼)等,當然,在最最 後還會介紹如果將驅動嵌入到LInux核心中,這樣Android在啟動是就自動擁有了這個驅動。

      想學習Android底層開發的童鞋可以通過本文完全掌握開發基於Android的LInux驅動的完整步驟。在《Android深度探索(卷1):HAL與驅動開發》隨書光碟片上有完整的實驗環境(VMWare Ubuntu Linux12.04LTS),如果嫌自己配置麻煩,可以從光碟片中複製該虛擬環境,虛擬檔案太大(3.6G),傳不上去,只能發文章了!

一、Linux驅動到底是個什麼東西

       對於從未接觸過驅動開發的程式員可能會感覺Linux驅動很神秘。感覺開發起來會很複雜。其實這完全是誤解。實際上Linux驅動和普通的LinuxAPI沒有本質的區別。只是使用Linux驅動的方式與使用Linux API的方式不同而已。

       在學習Linux驅動之前我們先來介紹一下Linux驅動的工作方式。如果讀者以前接觸過Windows或其他非Unix體系的作業系統,最好將它們的工作方式暫時忘掉,因為這些記憶會干擾我們理解Linux底層的一些細節。

      Linux驅動的工作和訪問方式是Linux的亮點之一,同時受到了業界的廣泛好評。Linux系統將每一個驅動都映射成一個檔案。這些檔案稱為裝置檔案 或驅動檔案,都儲存在/dev目錄中。這種設計理念使得與Linux驅動進行互動就像與普通檔案進行互動一樣容易。當然,也比訪問LinuxAPI更容 易。由於大多數Linux驅動都有與其對應的裝置檔案,因此與Linux驅動交換資料就變成了與裝置檔案交換資料。例如,向Linux印表機驅動發送一個 列印命令,可以直接使用C語言函數open開啟裝置檔案,再使用C語言函數ioctl向該驅動的裝置檔案發送列印命令。

     當然,要編寫Linux驅動程式還需要更進階的功能。如向印表機驅動寫入資料時,對於印表機驅動來說,需要接收這些被寫入的資料,並將它們通過PC的並 口、USB等連接埠發送給印表機。要實現這一過程就需要Linux驅動可以響應應用程式傳遞過來的資料。這就是Linux驅動的事件,雖然在C語言裡沒有事 件的概念,但卻有與事件類別似的概念,這就是回調(callback)函數。因此,編寫Linux驅動最重要的一步就是編寫回呼函數,否則與裝置檔案互動的 資料將無法得到處理。圖6-1是應用軟體、裝置檔案、驅動程式、硬體之間的關係。

二、編寫Linux驅動程式的步驟

      Linux 驅動程式與其他類型的Linux程式一樣,也有自己的規則。對於剛開始接觸Linux驅動開發的讀者可能對如何開發一個LInux驅動程式還不是太瞭解。 為瞭解決這部分讀者的困惑,本節給出了編寫一個基本的Linux驅動的一般步驟。讀者可以按著這些步驟循序漸進地學習Linux驅動開發。

第1步:建立Linux驅動骨架(裝載和卸載Linux驅動)

     任何類型的程式都有一個基本的結構,例如,C語言需要有一個入口函數main。Linux驅動程式也不例外。Linux核心在使用驅動時首先需要裝載驅動。 在裝載過程中需要進行一些初始化工作,例如,建立裝置檔案,分配記憶體位址空間等。當Linux系統退出時需要卸載Linux驅動,在卸載的過程中需要釋放 由Linux驅動佔用的資源,例如,刪除裝置檔案、釋放記憶體位址空間等。在Linux驅動程式中需要提供兩個函數來分別處理驅動初始化和退出的工作。這兩 個函數分別用module_init和module_exit宏指定。Linux驅動程式一般都都需要指定這兩個函數,因此包含這兩個函數以及指定這兩個 函數的兩個宏的C程式檔案也可看作是Linux驅動的骨架。

第2步:註冊和登出裝置檔案

     任何一個Linux驅動都需要有一個裝置檔案。否則應用程式將無法與驅動程式互動。建立裝置檔案的工作一般在第1步編寫的處理Linux初始化工作的函數中 完成。刪除裝置檔案一般在第1步編寫的處理Linux退出工作的函數中完成。可以分別使用misc_register和misc_deregister函 數建立和移除裝置檔案。

第3步:指定與驅動相關的資訊

     驅動程式是自描述的。例 如,可以通過modinfo命令擷取驅動程式的作者姓名、使用的開源協議、別名、驅動描述等資訊。這些資訊都需要在驅動原始碼中指定。通過 MODULE_AUTHOR、MODULE_LICENSE 、MODULE_ALIAS 、MODULE_DESCRIPTION等宏可以指定與驅動相關的資訊。

第4步:指定回呼函數

     Linux 驅動包含了多種動作,也可稱為事件。例如,向裝置檔案寫入資料時會觸發“寫”事件,Linux系統會調用對應驅動程式的write回呼函數,從裝置檔案讀 資料時會觸發“讀”事件,Linux系統會調用對應驅動程式的read回呼函數。一個驅動程式並不一定要指定所有的回呼函數。回呼函數會通過相關機制進行 註冊。例如,與裝置檔案相關的回呼函數會通過misc_register函數進行註冊。

第5步:編寫商務邏輯

     這 一步是Linux驅動的核心部分。光有骨架和回呼函數的Linux驅動是沒有任何意義的。任何一個完整的Linux驅動都會做一些與其功能相關的工作,如 印表機驅動會向印表機發送列印指令。COM驅動會根據傳輸數率進行資料互動。具體的商務邏輯與驅動的功能有關。商務邏輯可能有多個函數、多個檔案甚至是多 個Linux驅動模組組成。具體的實現讀者可以根據實際情況而定。

第6步:編寫Makefile檔案

     Linux核心原始碼的編譯規則是通過Makefile檔案定義的。因此編寫一個新的Linux驅動程式必須要有一個Makefile檔案。

第7步:編譯Linux驅動程式

     Linux驅動程式可以直接編譯進核心,也可以作為模組單獨編譯。

第8步:安裝和卸載Linux驅動

    如果將Linux驅動編譯進核心,只要Linux使用該核心,驅動程式就會自動裝載。如果Linux驅動程式以模組單獨存在,需要使用insmod或modprobe命令裝載Linux驅動模組,使用rmmod命令卸載Linux驅動模組。

  上面8步中的前5步是關於如何編寫Linux驅動程式的,通過後3步可以使Linux驅動正常工作。

三、編寫Linux驅動程式前的準備工作

     本例的Linux驅動原始碼並未與linux核心原始碼放在一起,而是單獨放在一個目錄。首先使用下面的命令建立存放Linux驅動程式的目錄。

# mkdir –p  /root/drivers/ch06/word_count

# cd  /root/drivers/ch06/word_count

      然後使用下面的命令建立驅動原始碼檔案(word_count.c)

# echo '' > word_count.c

      最後編寫一個Makefile檔案,實際上這是6.2節介紹的編寫Linux驅動程式的第6步。當熟悉編寫Linux驅動程式的步驟後可以不按6.2節介紹的順序來編寫Linux驅動。

# echo 'obj-m := word_count.o'  > Makefile

     其中obj-m表示將Linux驅動作為模組(.ko檔案)編譯。如果使用obj-y,則將Linux驅動編譯進Linux核心。obj-m或obj-y需
要使用“:=”賦值。如果obj-m或obj-y的值為word_count.o,表示make命令會把Linux驅動原始碼目錄中的
word_count.c或word_count.s檔案編譯成word_count.o檔案。如果使用obj-m,word_count.o會被串連進
word_count.ko檔案,然後使用insmod或modprobe命令裝載word_count.ko。如果使用obj-
y,word_count.o會被串連進built-in.o檔案,最終會被串連進核心。其中built-in.o檔案是串連同一類程式的.o檔案產生的
中間目標檔案。例如,所有的字元裝置驅動程式會最終產生一個built-in.o檔案。讀者可以在<Linux核心原始碼目
錄>/drivers/char目錄找到一個built-in.o檔案。該目標檔案包含了所有可串連進Linux核心的字元驅動(通過make
menuconfig命令可以配置每一個驅動及其他核心程式是否允許編譯進核心,關於配置Linux核心的技術詳見4.2.4節介紹)。

      如果Linux驅動依賴其他程式,如process.c、data.c。需要按如下方式編寫Makefile檔案。

obj-m := word_count.o

word_count-y := process.o  data.o

其中依賴檔案要使用module-y或module-objs指定。module表示模組名,如word_count。

四、編寫Linux驅動程式的骨架

     現在編寫Linux驅動程式的骨架部分,也就是前面介紹的第1步。骨架部分主要是Linux驅動的初始化和退出函數,代碼如下:

    #include <linux/module.h>      #include <linux/init.h>      #include <linux/kernel.h>      #include <linux/fs.h>      #include <linux/miscdevice.h>      #include <asm/uaccess.h>            //  初始化Linux驅動      static int word_count_init(void)      {          //  輸出日誌資訊          printk("word_count_init_success\n");          return 0;      }      // 退出Linux驅動      static void word_count_exit(void)      {          //  輸出日誌資訊         printk("word_count_init_exit_success\n");      }      //  註冊初始化Linux驅動的函數      module_init(word_count_init);      //  註冊退出Linux驅動的函數      module_exit(word_count_exit);     

       在上面的代碼中使用了printk函數。該函數用於輸出日誌資訊(關於printk函數的詳細用法將在10.1節詳細介紹)。printk函數與 printf函數的用法類似。有的讀者可能會有疑問,為什麼不用printf函數呢?這裡就涉及到一個Linux核心程式可以調用什麼,不可以調用什麼的 問題。Linux系統將記憶體分為了使用者空間和核心空間,這兩個空間的程式不能直接存取。printf函數運行在使用者空間,printk函數運行在核心空 間。因此,屬於核心程式的Linux驅動是不能直接存取printf函數的。就算包含了stdio.h標頭檔,在編譯Linux驅動時也會拋出 stdio.h檔案沒找到的錯誤。當然,運行在使用者空間的程式也不能直接調用printk函數。那麼是不是使用者空間和核心空間的程式就無法互動了呢?答案 是否定的。否則這兩塊記憶體不就成了孤島了嗎。運行在這兩塊記憶體中的程式之間互動的方法很多。其中裝置檔案就是一種主要的互動方式(在後面的章節還會介紹 /proc虛擬檔案的互動方式)。如果使用者空間的程式要訪問核心空間,只要做一個可以訪問核心空間的驅動程式,然後使用者空間的程式通過裝置檔案與驅動程式 進行互動即可。

      看到這可能有的讀者疑問更大了。Linux驅動程式無法直接存取運行在使用者空間的程式,那麼很多功能就都得自己實現了。例如,在C語言中會經常使用 malloc函數動態分配記憶體空間,該函數在Linux驅動程式中是無法使用的。那麼如何在Linux驅動程式中動態分配記憶體空間呢?解決類似的問題也很 簡單。既然Linux驅動無法直接調用運行在使用者空間的函數,那麼在Linux核心中就必須要提供替代品。讀者可以進入<Linux核心源代 碼>/include目錄,該目錄的各個子目錄中包含了大量的C語言標頭檔。這些標頭檔中定義的函數、宏等資源就是運行在使用者空間的程式的替代品。 運行在使用者空間的函數庫對應的標頭檔在/usr/include目錄中。剛才提到的malloc函數在核心空間的替代品是kmalloc(需要包含 slab.h標頭檔,#include  <linux/slab.h>)。

注意:使用者空 間與核心空間完成同樣或類似功能的函數、宏等資源的名稱並不一定相同,有的名稱類似,如malloc和kmalloc,有的完全是兩個不同的名字:如 atoi(使用者空間)和simple_strtol(核心空間)、itoa(使用者空間)和snprintf(核心空間)。讀者在使用核心相關資源時要注意 在一點。

     如果讀者想看看前面編寫的程式的效果,可以使用下面的命令編譯Linux驅動原始碼(X86架構)。

# make  -C /usr/src/linux-headers-3.0.0-15-generic M=/root/drivers/ch06/word_count

     在測試Linux驅動未必一定在Android裝置上完成。因為Android系統和Ubuntu Linux以及其他Linux發行版本都是基於Linux核心的,大多數Linux驅動程式可以在Ubuntu Linux或其他Linux發行版上測試完再重新用交叉編譯器編譯成基於ARM架構的目標檔案,然後再安裝到Android上即可正常運行。由於編譯 Linux核心原始碼需要使用Linux核心的標頭檔。為了在Ubuntu Linux上測試驅動程式,需要使用-C命令列參數指定Linux核心標頭檔的目錄(/usr/src/linux-headers-3.0.0-15- generic)。其中linux-headers-3.0.0-15-generic目錄是Linux核心原始碼目錄,在該目錄中只有include子 目錄有實際的標頭檔,其他目錄只有Makefile和其他一些設定檔,並不包含Linux核心原始碼。該目錄就是為了開發當前Linux核心版本的驅動 及其他核心程式而提供的(因為在編譯Linux驅動時產生目標檔案只需要標頭檔,在進行目標檔案連結時只要有相關的目標檔案即可,並不需要原始碼檔案)。 如果以模組方式編譯Linux驅動程式,需要使用M指定驅動程式所在的目錄(M= root/drivers/ch06/word_count)。

注意:如果讀者使用的Linux發行版採用了其他Linux核心,需要為-C命令列參數設定正確的路徑。

    執行上面的命令後,會輸出6-2所示資訊。從這些資訊可以看出,已經將word_count.c檔案編譯成了Linux驅動模組檔案word_count.ko。

      使用ls命令列出/root/drivers/ch06/word_count目錄中的檔案後發現,除了多了幾個.o和.ko檔案,還多了一些其他的檔案,6-3所示。這些檔案是有編譯器自動產生的,一般並不需要管這些檔案的內容。

     本文編寫的Linux驅動程式雖然什麼實際的功能都沒有,但已經可以作為驅動程式安裝在Linux核心空間了。讀者可以使用下面的命令安裝、查看、卸載Linux驅動,也可以查看由驅動程式輸出的日誌資訊(執行下面命令時需要先進入word_count目錄)。

安裝Linux驅動

# insmod word_count.ko

查看word_count是否成功安裝

# lsmod | grep word_count

卸載Linux驅動

# rmmod word_count

查看由Linux驅動輸出的日誌資訊

# dmesg | grep word_count | tail –n 2

執行上面的命令後,如果輸出6-4所示的資訊說明讀者已成功完成本節的學習,可以繼續看下一節了。

     dmesg命令實際上是從/var/log/messages(Ubuntu Linux 10.04)或/var/log/syslog(Ubuntu Linux11.10)檔案中讀取的日誌資訊,因此也可以執行下面的命令擷取由Linux驅動輸出的日誌資訊。

# cat /var/log/syslog | grep word_count | tail –n 2

    執行上面的命令後會輸出更多的資訊,6-5所示。

開發可統計單詞個數的Android驅動程式(2)

本文節選至《Android深度探索(卷1):HAL與驅動開發》, 接下來幾篇文章將詳細闡述如何開發ARM架構的Linux驅動,並分別利用android程式、NDK、可執行檔測試Linux驅動。可在ubuntu Linux、Android模擬器和S3C6410開發板(可以選購OK6410-A開發板,需要刷Android)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.