MTK Androiod HAL如何向上層提供接口

Android中HAL如何向上層提供接口總結

轉自:http://blog.csdn.net/flydream0/article/details/7086273html

參考文獻:linux

http://blog.csdn.net/luoshengyang/article/details/6573809express

http://blog.csdn.net/hongtao_liu/article/details/6060734apache

 

1.什麼是HAL?


 

HAL的全稱是Hardware Abstraction Layer,即硬件抽象層.其架構圖以下:數據結構

 

 

Android的HAL是爲了保護一些硬件提供商的知識產權而提出的,是爲了避開linux的GPL束縛。思路是把控制硬件的動做都放到了Android HAL中,而linux driver僅僅完成一些簡單的數據交互做用,甚至把硬件寄存器空間直接映射到user space。而Android是基於Aparch的license,所以硬件廠商能夠只提供二進制代碼,因此說Android只是一個開放的平臺,並非一個開源的平臺。也許也正是由於Android不聽從GPL,因此Greg Kroah-Hartman纔在2.6.33內核將Andorid驅動從linux中刪除。GPL和硬件廠商目前仍是有着沒法彌合的裂痕。Android想要把這個問題處理好也是不容易的。架構

總結下來,Android HAL存在的緣由主要有:app

1. 並非全部的硬件設備都有標準的linux kernel的接口less

2. KERNEL DRIVER涉及到GPL的版權。某些設備製造商並不緣由公開硬件驅動,因此纔去用HAL方式繞過GPL。函數

3. 針對某些硬件,Android有一些特殊的需求.post

 

2.與接口相關的幾個結構體


 

首先來看三個與HAL對上層接口有關的幾個結構體:

[html] view plaincopy
  1. struct hw_module_t;                      //模塊類型  
  2. struct hw_module_methods_t;      //模塊方法  
  3. struct hw_device_t;                      //設備類型  
這幾個數據結構是在Android工做目錄/hardware/libhardware/include/hardware/hardware.h文件中定義.
 
 
 

3.解釋


 

通常來講,在寫HAL相關代碼時都得包含這個hardware.h頭文件,因此有必要先了解一下這個頭文件中的內容.

 

[cpp] view plaincopy
 
  1. /* 
  2.  * Copyright (C) 2008 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.  #ifndef ANDROID_INCLUDE_HARDWARE_HARDWARE_H  
  17.  #define ANDROID_INCLUDE_HARDWARE_HARDWARE_H 
  18.  #include <stdint.h>  
  19.  #include <sys/cdefs.h>  
  20.  #include <cutils/native_handle.h>  
  21.  #include <system/graphics.h>   
  22. __BEGIN_DECLS  
  23.   
  24. /* 
  25.  * Value for the hw_module_t.tag field 
  26.  */  
  27.   
  28. #define MAKE_TAG_CONSTANT(A,B,C,D) (((A) << 24) | ((B) << 16) | ((C) << 8) | (D))  
  29.   
  30. #define HARDWARE_MODULE_TAG MAKE_TAG_CONSTANT('H', 'W', 'M', 'T')  
  31. #define HARDWARE_DEVICE_TAG MAKE_TAG_CONSTANT('H', 'W', 'D', 'T')  
  32.   
  33. struct hw_module_t;  
  34. struct hw_module_methods_t;  
  35. struct hw_device_t;  
  36.   
  37. /** 
  38.  * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM 
  39.  * and the fields of this data structure must begin with hw_module_t 
  40.  * followed by module specific information. 
  41.  */  
  42.  //每個硬件模塊都每必須有一個名爲HAL_MODULE_INFO_SYM的數據結構變量,它的第一個成員的類型必須爲hw_module_t  
  43.  typedef struct hw_module_t {  
  44.            /** tag must be initialized to HARDWARE_MODULE_TAG */  
  45.            uint32_t tag;  
  46.            /** major version number for the module */  
  47.            uint16_t version_major;  
  48.   
  49.            /** minor version number of the module */  
  50.            uint16_t version_minor;  
  51.   
  52.            /** Identifier of module */  
  53.            const char *id;  
  54.   
  55.            /** Name of this module */  
  56.            const char *name;  
  57.   
  58.           /** Author/owner/implementor of the module */  
  59.           const char *author;  
  60.   
  61.           /** Modules methods模塊方法列表,指向hw_module_methods_t */   
  62.           struct hw_module_methods_t* methods;  
  63.   
  64.           /** module's dso */  
  65.           void* dso;  
  66.   
  67.           /** padding to 128 bytes, reserved for future use */  
  68.           uint32_t reserved[32-7];  
  69.   
  70.   } hw_module_t;  
  71.   

         

    //硬件模塊方法列表的定義,這裏只定義了一個open函數 

  1. typedef struct hw_module_methods_t {                   
  2.             /** Open a specific device */  
  3.             int (*open)(const struct hw_module_t* module, const char* id, //注意這個open函數明確指出第三個參數的類型爲struct hw_device_t**  
  4.             struct hw_device_t** device);  
  5. } hw_module_methods_t;  
  6.   

 

 

  1. /** 
  2.  * Every device data structure must begin with hw_device_t 
  3.  * followed by module specific public methods and attributes. 
  4.  */  
  5. //每個設備數據結構的第一個成員函數必須是hw_device_t類型,其次纔是各個公共方法和屬性  
  6. typedef struct hw_device_t {  
  7.     /** tag must be initialized to HARDWARE_DEVICE_TAG */  
  8.     uint32_t tag;  
  9.   
  10.     /** version number for hw_device_t */  
  11.     uint32_t version;  
  12.   
  13.     /** reference to the module this device belongs to */  
  14.     struct hw_module_t* module;  
  15.   
  16.     /** padding reserved for future use */  
  17.     uint32_t reserved[12];  
  18.   
  19.     /** Close this device */  
  20.     int (*close)(struct hw_device_t* device);  
  21.   
  22. } hw_device_t;  
  23.   
  24. /** 
  25.  * Name of the hal_module_info 
  26.  */  
  27. #define HAL_MODULE_INFO_SYM         HMI  
  28.   
  29. /** 
  30.  * Name of the hal_module_info as a string 
  31.  */  
  32. #define HAL_MODULE_INFO_SYM_AS_STR  "HMI"  
  33.   
  34. /** 
  35.  * Get the module info associated with a module by id. 
  36.  * 
  37.  * @return: 0 == success, <0 == error and *module == NULL 
  38.  */  
  39. int hw_get_module(const char *id, const struct hw_module_t **module);  
  40.   
  41. /** 
  42.  * Get the module info associated with a module instance by class 'class_id' 
  43.  * and instance 'inst'. 
  44.  * 
  45.  * Some modules types necessitate multiple instances. For example audio supports 
  46.  * multiple concurrent interfaces and thus 'audio' is the module class 
  47.  * and 'primary' or 'a2dp' are module interfaces. This implies that the files 
  48.  * providing these modules would be named audio.primary.<variant>.so and 
  49.  * audio.a2dp.<variant>.so 
  50.  * 
  51.  * @return: 0 == success, <0 == error and *module == NULL 
  52.  */  
  53. int hw_get_module_by_class(const char *class_id, const char *inst,  
  54.                            const struct hw_module_t **module);  
  55.   
  56. __END_DECLS  
  57.   
  58. #endif  /* ANDROID_INCLUDE_HARDWARE_HARDWARE_H */  
由以上內容能夠看出(typedef struct hw_module_t ,typedef struct hw_device_t),若是咱們要寫一個自定義設備的驅動的HAL層時,咱們得首先自定義兩個數據結構:

 

假設咱們要作的設備名爲XXX:

在頭文件中定義:XXX.h

[cpp] view plaincopy
 
  1. /*定義模塊ID*/  
  2. #define XXX_HARDWARE_MODULE_ID "XXX"  
  3.   
  4. /*硬件模塊結構體*/  
  5. //見hardware.h中的hw_module_t定義的說明,xxx_module_t的第一個成員必須是hw_module_t類型,其次纔是模塊的一此相關信息,固然也能夠不定義,  
  6. //這裏就沒有定義模塊相關信息  
  7. struct xxx_module_t {  
  8.     struct hw_module_t common;  
  9. };  
  10.   
  11. /*硬件接口結構體*/  
  12. //見hardware.h中的hw_device_t的說明,要求自定義xxx_device_t的第一個成員必須是hw_device_t類型,其次纔是其它的一些接口信息.   
  13. struct xxx_device_t {  
  14.     struct hw_device_t common;  
  15.         //如下成員是HAL對上層提供的接口或一些屬性  
  16.         int fd;  
  17.     int (*set_val)(struct xxx_device_t* dev, int val);  
  18.     int (*get_val)(struct xxx_device_t* dev, int* val);  
  19. };  
注:特別注意xxx_device_t的結構定義,這個纔是HAL向上層提供接口函數的數據結構,其成員就是咱們想要關心的接口函數.

接下來咱們在實現文件XXX.c文件中定義一個xxx_module_t的變量:

 

[cpp] view plaincopy
 
  1. /*模塊實例變量*/  
  2. struct xxx_module_t HAL_MODULE_INFO_SYM = {    //變量名必須爲HAL_MODULE_INFO_SYM,這是強制要求的,你要寫Android的HAL就得遵循這個遊戲規則,  
  3.                                                //見hardware.h中的hw_module_t的類型信息說明.  
  4.         common: {  
  5.         tag: HARDWARE_MODULE_TAG,  
  6.         version_major: 1,  
  7.         version_minor: 0,  
  8.         id: XXX_HARDWARE_MODULE_ID,    //頭文件中有定義  
  9.         name: MODULE_NAME,  
  10.         author: MODULE_AUTHOR,  
  11.         methods: &xxx_module_methods,  //模塊方法列表,在本地定義  
  12.     }  
  13. };  

注意到上面有HAL_MODULE_INFO_SYM變量的成員common中包含一個函數列表xxx_module_methods,而這個成員函數列表是在本地自定義的。那麼這個成員函數列是否是就是HAL向上層提供函數的地方呢?很失望,不是在這裏,前面咱們已經說過了,是在xxx_device_t中定義的,這個xxx_module_methods實際上只提供了一個open函數,就至關於只提供了一個模塊初始化函數.其定義以下:

 

 

[cpp] view plaincopy
 
  1. /*模塊方法表*/  
  2. static struct hw_module_methods_t xxx_module_methods = {  
  3.     open: xxx_device_open  
  4. };  
注意到,上邊的函數列表中只列出了一個xxx_device_open函數,這個函數也是須要在本地實現的一個函數。前面說過,這個函數只至關於模塊初始化函數。

 

那麼HAL又究竟是怎麼將xxx_device_t中定義的接口提供到上層去的呢?

且看上面這個函數列表中惟一的一個xxx_device_open的定義:

 

[cpp] view plaincopy
 
  1. static int xxx_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) {  
  2.     struct xxx_device_t* dev;  
  3.     dev = (struct hello_device_t*)malloc(sizeof(struct xxx_device_t));//動態分配空間  
  4.       
  5.     if(!dev) {  
  6.         LOGE("Hello Stub: failed to alloc space");  
  7.         return -EFAULT;  
  8.     }  
  9.   
  10.     memset(dev, 0, sizeof(struct xxx_device_t));  
  11.         //對dev->common的內容賦值,  
  12.         dev->common.tag = HARDWARE_DEVICE_TAG;  
  13.     dev->common.version = 0;  
  14.     dev->common.module = (hw_module_t*)module;  
  15.     dev->common.close = xxx_device_close;  
  16.         //對dev其它成員賦值  
  17.         dev->set_val = xxx_set_val;  
  18.     dev->get_val = xxx_get_val;  
  19.   
  20.     if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) {  
  21.         LOGE("Hello Stub: failed to open /dev/hello -- %s.", strerror(errno));  
  22.         free(dev);  
  23.         return -EFAULT;  
  24.     }  
  25.           
  26.         //輸出&(dev->common),輸出的並非dev,而是&(dev->common)!(common內不是隻包含了一個close接口嗎?)  
  27.     *device = &(dev->common);  
  28.     LOGI("Hello Stub: open /dev/hello successfully.");  
  29.   
  30.     return 0;  
  31. }  
經驗告訴咱們,通常在進行模塊初始化的時候,模塊的接口函數也會「註冊」,上面是模塊初始化函數,那麼接口註冊在哪?因而咱們找到*device =&(dev->common);這行代碼,可問題是,這樣一來,返回給調用者不是&(dev->common)嗎?而這個dev->common僅僅只包含了一個模塊關閉接口!到底怎麼回事?爲何不直接返回dev,dev下不是提供全部HAL向上層接口嗎?

 

在回答上述問題以前,讓咱們先看一下這xxx_device_open函數原型,仍是在hardware.h頭文件中,找到下面幾行代碼:

 

[cpp] view plaincopy
 
  1. typedef struct hw_module_methods_t {  
  2.     /** Open a specific device */  
  3.     int (*open)(const struct hw_module_t* module, const char* id,  
  4.             struct hw_device_t** device);  
  5.   
  6. } hw_module_methods_t;  
這是方法列表的定義,明確要求了方法列表中有且只一個open方法,即至關於模塊初始化方法,且,這個方法的第三個參數明確指明瞭類型是struct hw_device_t **,而不是用戶自定義的xxx_device_t,這也就是解譯了在open函數實現內爲何輸出的是&(dev->common)而不是dev了,原來返回的類型在hardware.h中的open函數原型中明確指出只能返回hw_device_t類型.

 

但是,dev->common不是隻包含close接口嗎?作爲HAL的上層,它又是怎麼"看獲得"HAL提供的所有接口的呢?

接下來,讓咱們來看看作爲HAL上層,它又是怎麼使用由HAL返回的dev->common的:

參考: 在Ubuntu爲Android硬件抽象層(HAL)模塊編寫JNI方法提供Java訪問硬件服務接口 這篇文章,從中能夠看到這麼幾行代碼:

 

[cpp] view plaincopy
 
  1. /*經過硬件抽象層定義的硬件模塊打開接口打開硬件設備*/    
  2. static inline int hello_device_open(const hw_module_t* module, struct hello_device_t** device) {    
  3.      return module->methods->open(module, HELLO_HARDWARE_MODULE_ID, (struct hw_device_t**)device);    
  4. }    
因而可知,返回的&(dev->common)最終會返回給struce hello_device_t **類型的輸出變量device,換句話說,類型爲hw_device_t的dev->common在初始化函數open返回後,會強制轉化爲xxx_device_t來使用,終於明白了,原來如此!另外,在hardware.h中對xxx_device_t類型有說明,要求它的第一個成員的類型必須是hw_device_t,原來是爲了HAL上層使用時的強制轉化的目的,若是xxx_device_t的第一個成員類型不是hw_device_t,那麼HAL上層使用中強制轉化就沒有意義了,這個時候,就真的「看不到」HAL提供的接口了.

 

 

此外,在hardware.h頭文件中,還有明確要求定義xxx_module_t類型時,明確要求第一個成員變量類型必須爲hw_module_t,這也是爲了方便找到其第一個成員變量common,進而找到本地定義的方法列表,從而調用open函數進行模塊初始化.

 

綜上所述,HAL是經過struct xxx_device_t這個結構體向上層提供接口的.

即:接口包含在struct xxx_device_t這個結構體內。

而具體執行是經過struct xxx_module_t HAL_MODULE_INFO_SYM這個結構體變量的函數列表成員下的open函數來返回給上層的.

相關文章
相關標籤/搜索