硬件抽象層(HAL)_第1頁
硬件抽象層(HAL)_第2頁
硬件抽象層(HAL)_第3頁
硬件抽象層(HAL)_第4頁
硬件抽象層(HAL)_第5頁
已閱讀5頁,還剩28頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領

文檔簡介

1、第第9講講 硬件抽象層(硬件抽象層(HAL)講師:李寧主要內(nèi)容 什么是HAL 為什么要在Android在添加HAL 編寫和測試基于HAL的LED驅(qū)動什么是HAL HAL(Hardware Abstraction Layer,硬件抽象層)是建立在Linux驅(qū)動之上的一套動態(tài)庫。這套動態(tài)庫并不屬于Linux內(nèi)核,而是屬于Linux內(nèi)核層之上的系統(tǒng)運行庫層。Google為Android增加HAL的主要目的除盡量避免應用程序直接訪問Linux驅(qū)動外,還有一個重要原因,那就是保護“私人財產(chǎn)”。對于那些既想發(fā)布基于Android的Linux驅(qū)動程序,又不想將核心業(yè)務邏輯公開的企業(yè)或個人,HAL簡直就是福音

2、。為什么要在Android中加入HAL 加入HAL的主要目的l 統(tǒng)一硬件的調(diào)用接口。由于HAL有標準的調(diào)用接口,所以可以利用HAL屏蔽Linux驅(qū)動復雜、不統(tǒng)一的接口。l 解決了GPL版權(quán)問題。由于Linux內(nèi)核基于GPL協(xié)議,而Android基于Apache Licence 2.0協(xié)議。因此Google玩了個“穿越”,將原本位于Linux內(nèi)核中的Linux驅(qū)動的敏感代碼向上移了一個層次。這樣這些敏感代碼就擺脫了GPL協(xié)議的束縛。那寫不想開源的Linux驅(qū)動作者也就沒必要開源了。l 針對一些特殊的要求。對于有些硬件,可能需要訪問一些用戶空間的資源,或在內(nèi)核空間不方便完成的工作以及特殊需求。在這

3、種情況下,可以利用位于用戶空間的HAL代碼來輔助Linux驅(qū)動完成一些工作。Android HAL的舊架構(gòu) Android HAL的新架構(gòu) Android HAL程序庫的路徑 Android HAL的源代碼存儲的位置并不固定。一般會存儲在/hardware目錄中。其中/hardware/libhardware_legacy用于保存舊的HAL架構(gòu)的源代碼。新HAL架構(gòu)的源代碼在/hardware/libhardware目錄中,當然,這些源代碼可以放在/hardware或其他的目錄。最終編譯生成的.so文件主要放在Android系統(tǒng)的/system/lib/hw目錄,也可以放在其他的目錄。精簡LE

4、D驅(qū)動 基于HAL的LED驅(qū)動去掉了所有與讀寫寄存器規(guī)則相關(guān)的代碼,只保留了創(chuàng)建設備文件已經(jīng)與寄存器交互的代碼(不涉及到任何規(guī)則,只是將數(shù)據(jù)簡單地寫入指定的寄存器,或從指定的寄存器讀取數(shù)據(jù))。 LED驅(qū)動利用了設備文件的read和write函數(shù)來讀寫指定的寄存器?;驹硎侵粡闹付拇嫫髯x取或?qū)懭?個字節(jié)。第1個字節(jié)用于指定讀寫的動作以及寄存器。后4個字節(jié)是讀寫的實際的數(shù)據(jù)(因為LED驅(qū)動只涉及到操作一個int類型數(shù)據(jù)的寄存器,因此使用4個字節(jié)個來表示一個int類型的數(shù)據(jù))。在與LED驅(qū)動交互是,只要向設備文件(/dev/s3c6410_leds_hal)讀取或發(fā)送5個字節(jié)的數(shù)據(jù),就可以讀寫指

5、定的寄存器。測試讀寫寄存器操作 由于LED驅(qū)動程序的設備文件接收的不是字符串,而是字節(jié)類型的數(shù)據(jù)(字節(jié)數(shù)組),因此需要單獨做一個程序向設備文件寫入字節(jié)形式的數(shù)據(jù),或從設備文件中讀取字節(jié)類型的數(shù)據(jù)。 命令行參數(shù)來傳遞設備文件名、字節(jié)數(shù)和要傳遞的字節(jié)等信息。命令行語法格式如下:rwdev byte1 byte2 . byten編譯rw_dev.c程序arm-gcc -static -o /root/drivers/read_write_dev/rwdev /root/drivers/read_write_dev/rw_dev.c調(diào)用LED驅(qū)動的HAL程序庫(1) 任何被系統(tǒng)自動調(diào)用的程序都會有一個

6、標準的接口。這個接口相當與一個約定的規(guī)則。不管任何程序,只要遵循這個規(guī)則,就可以成功被調(diào)用。例如,C語言可執(zhí)行程序都會有一個main函數(shù),系統(tǒng)中執(zhí)行程序是都會尋找main函數(shù)來執(zhí)行;Linux驅(qū)動也有多個接口,最常用的就是init和exit函數(shù),除此之外,還有與設備文件相關(guān)的read、write、ioctl等函數(shù)。只要Linux驅(qū)動程序安裝接口的要求定義和實現(xiàn),就可以成功安裝在Linux驅(qū)動中。調(diào)用LED驅(qū)動的HAL程序庫(2) 既然HAL程序庫也可以被Android系統(tǒng)自動調(diào)用,那么自然也擁有標準的接口。只不過這個接口不是函數(shù),而是一個固定名稱的結(jié)構(gòu)體變量HAL_MODULE_INFO_SY

7、M。也就是說,所有的HAL程序都必須要有一個HAL_MODULE_INFO_SYM變量,并且初始化該結(jié)構(gòu)體變量的common成員變量。調(diào)用LED驅(qū)動的HAL程序庫(3) 第1步:定義結(jié)構(gòu)體定義結(jié)構(gòu)體和宏和宏 編寫HAL程序庫需要使用到3個非常重要的結(jié)構(gòu)體(hw_module_t、hw_device_t和hw_module_methods_t),在第1步需要定義兩個新的結(jié)構(gòu)體,這兩個結(jié)構(gòu)體的第1個變量的類型必須是hw_module_t和hw_device_t。一般還需要為HAL模塊定義一個ID。實際上在這1步就是編寫leds_hal.h頭文件的代碼。調(diào)用LED驅(qū)動的HAL程序庫(4) typed

8、ef struct hw_module_t /* 模塊的Tag,值必須是HARDWARE_MODULE_TAG */ uint32_t tag; /* 模塊主版本號 */ uint16_t version_major; /* 模塊從版本號 */ uint16_t version_minor; /* 模塊的ID,通過該ID可以找到當前模塊 */ const char *id; /* 模塊名稱 */ const char *name; /* 模塊作者 */ const char *author; /* 與模塊相關(guān)的函數(shù)指針,都包含著hw_module_methods_t結(jié)構(gòu)體中 */ struct

9、 hw_module_methods_t* methods; /* 模塊的dso ,dlopen函數(shù)返回的HAL動態(tài)庫的handler */ void* dso; /*保留的空間 */ uint32_t reserved32-7; hw_module_t;調(diào)用LED驅(qū)動的HAL程序庫(5) 描述硬件設備(或稱為描述硬件設備(或稱為HAL設備)的結(jié)構(gòu)體設備)的結(jié)構(gòu)體hw_device_t。typedef struct hw_device_t /* 設備的Tag,值必須是HARDWARE_DEVICE_TAG */ uint32_t tag; /* 硬件設備的版本號 */ uint32_t ver

10、sion; /* 指向描述硬件模塊的hw_module_t結(jié)構(gòu)體指針 */ struct hw_module_t* module; /* 保留的內(nèi)存空間 */ uint32_t reserved12; /* 關(guān)閉設備的函數(shù)指針 */ int (*close)(struct hw_device_t* device); hw_device_t;調(diào)用LED驅(qū)動的HAL程序庫(6) 描述模塊入口函數(shù)的結(jié)構(gòu)體描述模塊入口函數(shù)的結(jié)構(gòu)體hw_module_methods_t。typedef struct hw_module_methods_t /* 打開設備是調(diào)用的open函數(shù)的指針 */ int (*op

11、en)(const struct hw_module_t* module, const char* id, struct hw_device_t* device); hw_module_methods_t; 在這3個結(jié)構(gòu)體中,hw_module_t是最先使用到的,然后通過hw_module_t.methods找到hw_module_methods_t.open函數(shù),并調(diào)用該函數(shù)。這個open函數(shù)相當與HAL程序庫的入口函數(shù)。一般會在這個函數(shù)里打開設備文件,初始化hw_device_t結(jié)構(gòu)體設置一些控制硬件設備的函數(shù)。調(diào)用LED驅(qū)動的HAL程序庫(7) 在第1步先考慮hw_module_t和hw

12、_device_t兩個結(jié)構(gòu)體。HAL規(guī)則建議不直接使用hw_module_t和hw_device_t(直接使用這,而要新定義兩個結(jié)構(gòu)體,將hw_module_t和hw_device_t分別作為新結(jié)構(gòu)體的第1個變量的類型。就像leds_hal.h文件中的led_module_t和led_control_device_t。那么HAL為什么要這么建議呢?調(diào)用LED驅(qū)動的HAL程序庫(8) 在說明原因之前,先看一下led_device_open函數(shù)和led_control_device_t結(jié)構(gòu)體。static int led_device_open(const struct hw_module_t*

13、module, const char* name, struct hw_device_t* device) struct led_control_device_t struct hw_device_t hw_device; int (*set_on)(struct led_control_device_t *dev, int32_t led); int (*set_off)(struct led_control_device_t *dev, int32_t led);調(diào)用LED驅(qū)動的HAL程序庫(9) led_device_open函數(shù)將在NDK程序中被調(diào)用。該函數(shù)的最后1個參數(shù)類型是hw_d

14、evice_t*,不過在調(diào)用該函數(shù)時,傳進來的卻是led_control_device_t*。從這一點看。hw_device_t相當與led_control_device_t的父類(C語言中并沒有類的概念,這樣解釋只是便于理解,也可以稱為其父結(jié)構(gòu)體)。在調(diào)用led_device_open函數(shù)時將led_control_device_t*強行轉(zhuǎn)換成了hw_device_t*。對于C語言來說,這樣的轉(zhuǎn)換要滿足一個條件,就是做為父結(jié)構(gòu)體(hw_device_t)的結(jié)構(gòu)體必須是子結(jié)構(gòu)體(led_control_device_t)的第1個變量的數(shù)據(jù)類型。調(diào)用LED驅(qū)動的HAL程序庫(10) 那么為什么要

15、這樣做強行轉(zhuǎn)換呢?主要是因為擴展的需要。因為在led_control_device_t結(jié)構(gòu)體中定義了兩個函數(shù)指針變量(set_on和set_off)。這兩個變量的名稱和參數(shù)個數(shù)、參數(shù)類型是任意指定的。但為了使HAL程序庫保持獨立性(可能會被多個NDK模塊使用,每個NDK模塊使用了不同的hw_device_t和hw_module_t的子結(jié)構(gòu)體),HAL程序庫在的方法只能使用hw_device_t和hw_module_t作為參數(shù)類型。而如果不使用hw_device_t和hw_module_t的父類,就意味這無法添加這種設備函數(shù)指針(set_on和set_off)等成員。那么這個HAL程序庫就成了中

16、看不中用的“東西”了。光有邏輯代碼,卻無法向外部提供與其交互的接口。調(diào)用LED驅(qū)動的HAL程序庫(11) 由于在led_module_t結(jié)構(gòu)體除了hw_module變量外,沒有任何其他的成員,因此,HAL_MODULE_INFO_SYM的類型可以直接定義成hw_module_t,代碼如下:struct hw_module_t HAL_MODULE_INFO_SYM = tag: HARDWARE_MODULE_TAG, version_major: 1, version_minor: 0, id: LED_HARDWARE_MODULE_ID,name: Sample LED HAL Stub

17、,author: Lining,methods: &led_module_methods,;調(diào)用LED驅(qū)動的HAL程序庫(12) 第第2步:編寫打開設備的步:編寫打開設備的open函數(shù)函數(shù) 設備的打開函數(shù)是HAL模塊的入口點。在本例中是led_device_open函數(shù)。設備打開函數(shù)主要做如下3項工作。l 初始化hw_device_t的子結(jié)構(gòu)體。除了設置也寫必要的變量外,還需要設置操作硬件的函數(shù)指針(本例是close、set_on和set_off)。其中set_on和set_off在調(diào)用HAL模塊的代碼中要使用到。close有系統(tǒng)自動調(diào)用。在這一步與close、set_on和set_o

18、ff慣量的函數(shù)還沒有定義,可以先把函數(shù)名寫上,或在定義了相關(guān)函數(shù)后再設置這些函數(shù)指針。l 打開設備文件。l 初始化寄存器。調(diào)用LED驅(qū)動的HAL程序庫(13) 第第3步:定義步:定義hw_module_methods_t結(jié)構(gòu)體變量結(jié)構(gòu)體變量HAL模塊需要hw_module_methods_t結(jié)構(gòu)體的open函數(shù)指針變量指定open入口函數(shù)。 第第4步:定義步:定義HAL_MODULE_INFO_SYM變量變量 所有的HAL模塊都必須有一個HAL_MODULE_INFO_SYM變量。該變量的類型一般為hw_module_t或其子結(jié)構(gòu)體。該變量初始化了一些變量,其中id和methods成員最重要。

19、id表示HAL模塊中Android系統(tǒng)中的索引。使用HAL模塊的程序并不是直接裝載.so文件,而是通過這個id找到并裝載HAL模塊。methods變量的值需要設置在第3步定義的hw_module_methods_t結(jié)構(gòu)體變量。當調(diào)用者通過id找到并裝載HAL模塊后,就會通過methods變量調(diào)用open入口函數(shù)來初始化設備。調(diào)用LED驅(qū)動的HAL程序庫(14) 第第5步:編寫卸載設備的步:編寫卸載設備的close函數(shù)函數(shù)當HAL模塊被卸載后會調(diào)用close函數(shù)。在本例中是led_device_close函數(shù)。該函數(shù)需要在第2步的led_device_open函數(shù)中賦給hw_device_t的c

20、lose成員變量。 第第6步:編寫控制設備的函數(shù)步:編寫控制設備的函數(shù)根據(jù)設備類型和功能的不同,這一步編寫的函數(shù)也有所不同。在本例中編寫了兩個控制函數(shù)(led_on和led_off),分別用來控制LED的開、關(guān)。led_on和led_off函數(shù)需要在第2步編寫的led_device_open函數(shù)中賦給led_control_device_t.set_on和led_control_device_t.set_off變量。編寫調(diào)用HAL程序庫的Service 調(diào)用HAL程序庫涉及到一個非常重要的hw_get_module函數(shù)。該函數(shù)可以通過在leds_hal.h中定義的LED_HARDWARE_MO

21、DULE_ID宏(led_hal)查找LED HAL模塊,并獲得led_module_t結(jié)構(gòu)體。然后調(diào)用led_module_t.hw_module.methods.open函數(shù)來初始化LED驅(qū)動。并通過open函數(shù)返回led_control_device_t結(jié)構(gòu)體。在led_control_device_t結(jié)構(gòu)體中包含了在HAL模塊中定義的控制LED驅(qū)動的函數(shù)指針(set_on和set_off)。為Service建立符號鏈接 ln -s /root/drivers/s3c6410_leds_hal/leds_hal_jni /working/android2.3.4_src/framewor

22、ks/base/services/leds_hal_jniHAL的存放路徑和命名規(guī)則(1) HAL程序庫(so文件)通常存放在/system/lib/hw目錄。文件名中一般都有一個default。例如,led_hal.default.so文件是LED驅(qū)動的HAL程序庫。那么這個存放目錄和文件名是我們的唯一選擇嗎?在回答這個問題之前,需要先查看一下調(diào)用HAL程序庫的核心函數(shù)hw_get_module的代碼,因為正是這個函數(shù)利用HAL模塊的ID找到了HAL程序庫的.so文件。所以一切的秘密都會在這個函數(shù)的揭開。hw_get_module函數(shù)位于hardware.c文件中。hardware.c文件的

23、完整路徑如下:/working/android2.3.4_src/hardware/libhardware/hardware.cHAL的存放路徑和命名規(guī)則(2) 在閱讀完hardware.c文件的代碼和注釋后,可以得出如下結(jié)論,這些結(jié)論也恰好回到了本節(jié)開始提出的問題。l HAL模塊庫文件的存放路徑有兩個:/system/lib/hw和/vendor/lib/hw。hw_get_module函數(shù)會先從/system/lib/hw目錄根據(jù)庫文件命名規(guī)則尋找?guī)煳募?。如?system/lib/hw目錄沒有庫文件,hw_get_module會按同樣的規(guī)則在/vendor/lib/hw目錄中尋找。l H

24、AL模塊庫文件的命名規(guī)則是ID.suffix.so。其中ID功過hw_get_module函數(shù)的id參數(shù)指定。suffix(后綴)通過在屬性文件中指定。l hw_get_module會在Android系統(tǒng)的屬性文件中根據(jù)variant_keys數(shù)組中定義的4個key依次查找suffix。如果未找到suffix,使用默認的suffix(default)。HAL的存放路徑和命名規(guī)則(3) 在上面的幾點多次提到了屬性文件,那么這個屬性文件到底是什么呢?實際上,Android系統(tǒng)的屬性文件共有如下4個。l /pl /system/pl /system/defau

25、pl /data/pHAL的存放路徑和命名規(guī)則(4) Android在啟動時會自動裝載這些屬性文件。如果在多個屬性文件中都定義了同一個Key和Value,那么只用第一個Key被獲取。例如,在/p文件中定義了duct.board的值為abc,而在/system/p文件中定義了duct.boardd的值為xyz。那么hw_get_module函數(shù)會把/p文件中的abc作為HAL模塊庫文件的后綴,而不會再讀取/system/p文件中的xyz。因此,HAL模塊的庫文件名是(假設ID是led_hal)led_hal.abc.so。HAL的存放路徑和命名規(guī)則(5) 4個屬性文件名在如下文件定義了4個宏。在以后的Android版本中有可能增加新的屬性文件。/working/android2.3.4_src/bionic/libc/include/sys/_system_proper

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論