在Ubuntu上為Android增加硬體抽象層(HAL)模組訪問Linux核心驅動程式(老羅學習筆記3),ubuntuandroid

來源:互聯網
上載者:User

在Ubuntu上為Android增加硬體抽象層(HAL)模組訪問Linux核心驅動程式(老羅學習筆記3),ubuntuandroid

在Android硬體抽象層(HAL)概要介紹和學習計劃一文中,我們簡要介紹了在Android系統為為硬體編寫驅動程式的方法。簡單來說,硬體驅動程式一方面分布在Linux核心中,另一方面分布在使用者空間的硬體抽象層中。接著,在Ubuntu上為Android系統編寫Linux核心驅動程式一文中舉例子說明了如何在Linux核心編寫驅動程式。在這一篇文章中,我們將繼續介紹Android系統硬體驅動程式的另一方面實現,即如何在硬體抽象層中增加硬體模組來和核心驅動程式互動。在這篇文章中,我們還將學習到如何在Android系統建立裝置檔案時用類似Linux的udev規則修改裝置檔案模式的方法。

      一. 參照在Ubuntu上為Android系統編寫Linux核心驅動程式一文所示,準備好樣本核心驅動序。完成這個核心驅動程式後,便可以在Android系統中得到三個檔案,分別是/dev/hello、/sys/class/hello/hello/val和/proc/hello。在本文中,我們將通過裝置檔案/dev/hello來串連硬體抽象層模組和Linux核心驅動程式模組。

      二. 進入到在hardware/libhardware/include/hardware目錄,建立hello.h檔案:

      USER-NAME@MACHINE-NAME:~/Android$ cd hardware/libhardware/include/hardware

      USER-NAME@MACHINE-NAME:~/Android/hardware/libhardware/include/hardware$ vi hello.h

      hello.h檔案的內容如下:

#ifndef ANDROID_HELLO_INTERFACE_H  #define ANDROID_HELLO_INTERFACE_H  #include <hardware/hardware.h>    __BEGIN_DECLS    /*--擴充C語言在編譯的時候按照C++編譯器進行統一處理,使得C++代碼能夠調用C編譯產生的中間代碼*/ /*定義模組ID*/  #define HELLO_HARDWARE_MODULE_ID "hello"    /*硬體模組結構體*/  struct hello_module_t {      struct hw_module_t common;  };    /*硬體介面結構體*/  struct hello_device_t {      struct hw_device_t common;      int fd;      int (*set_val)(struct hello_device_t* dev, int val);    /*--set_val什麼類型?什麼作用?以及後面這樣複用結構體 何用??--*/    int (*get_val)(struct hello_device_t* dev, int* val);  };    __END_DECLS    #endif  

/*--

hw_module_t:

/**  * Every hardware module must have a data structure named HAL_MODULE_INFO_SYM  * and the fields of this data structure must begin with hw_module_t  * followed by module specific information.  */  //每一個硬體模組都每必須有一個名為HAL_MODULE_INFO_SYM的資料結構變數,它的第一個成員的類型必須為hw_module_t  typedef struct hw_module_t {      /** tag must be initialized to HARDWARE_MODULE_TAG */      uint32_t tag;   // 初始化硬體模組標籤      /** major version number for the module */      uint16_t version_major;  //主模組版本號碼      /** minor version number of the module */      uint16_t version_minor;  //副模組版本號碼      /** Identifier of module */      const char *id;    //模組標識符        /** Name of this module */      const char *name;  //模組名字      /** Author/owner/implementor of the module */      const char *author;   //編寫作者      /** Modules methods */      //模組方法列表,指向hw_module_methods_t*      struct hw_module_methods_t* methods;      //硬體模組的方法      /** module's dso */      void* dso;    //DSO: Device Software Optimization,裝置軟體最佳化“安全維和組織”(DSO)      /** padding to 128 bytes, reserved for future use */      uint32_t reserved[32-7];    //填充到128位元組,保留以供將來使用  } hw_module_t;

 

--*/

   這裡按照Android硬體抽象層規範的要求,分別定義①模組ID、②模組結構體以及③硬體介面結構體。在硬體介面結構體中,fd表示裝置檔案描述符,對應我們將要處理的裝置檔案"/dev/hello",set_val和get_val為該HAL對上提供的函數介面。

      三. 進入到hardware/libhardware/modules目錄,建立hello目錄,並添加hello.c檔案。 hello.c的內容較多,我們分段來看。

      首先是包含相關標頭檔和定義相關結構:

#define LOG_TAG "HelloStub"       
/*--HelloStub:什麼作用?
答:

  HAL stub的架構比較簡單,三個結構體、兩個常量、一個函數,簡稱321架構,它的定義在:

  @hardware/libhardware/include/hardware/hardware.h

  @hardware/libhardware/hardware.c

--*/  #include <hardware/hardware.h>  #include <hardware/hello.h>  #include <fcntl.h>     //檔案控制#include <errno.h>     //出錯碼#include <cutils/log.h>     //?#include <cutils/atomic.h>  //?  #define DEVICE_NAME "/dev/hello"   //需要是路徑 ! #define MODULE_NAME "Hello"  #define MODULE_AUTHOR "shyluo@gmail.com"   //模組作者  /*裝置開啟和關閉介面*/  static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);  static int hello_device_close(struct hw_device_t* device);    /*裝置提供者*/  static int hello_set_val(struct hello_device_t* dev, int val);  static int hello_get_val(struct hello_device_t* dev, int* val);    /*模組方法表*/  
//硬體模組方法列表的定義,這裡只定義了一個open函數static struct hw_module_methods_t hello_module_methods = { open: hello_device_open }; /*模組執行個體變數*/ struct hello_module_t HAL_MODULE_INFO_SYM = { //HAL_MODULE_INFO_SYM: 上層調用時的入口(相當於main)!! common: { tag: HARDWARE_MODULE_TAG, version_major: 1, version_minor: 0, id: HELLO_HARDWARE_MODULE_ID, name: MODULE_NAME, author: MODULE_AUTHOR, methods: &hello_module_methods, //解釋看上 } };

      這裡,執行個體變數名必須為HAL_MODULE_INFO_SYM,tag也必須為HARDWARE_MODULE_TAG,這是Android硬體抽象層規範規定的。

-----

定義hello_device_open函數:

static int hello_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device) {      struct hello_device_t* dev;
   dev = (struct hello_device_t*)malloc(sizeof(struct hello_device_t));
    /*--將一個分配域的起始地址轉換成struct hello_device_t* 類型 如果此函數未能成功地執行(例如記憶體不足),則返回null 指標(NULL,'0')--*/ if(!dev) { LOGE("Hello Stub: failed to alloc space"); return -EFAULT; } memset(dev, 0, sizeof(struct hello_device_t)); //清空該段記憶體,然後該記憶體段重新賦值 dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0; dev->common.module = (hw_module_t*)module; dev->common.close = hello_device_close; dev->set_val = hello_set_val;dev->get_val = hello_get_val; if((dev->fd = open(DEVICE_NAME, O_RDWR)) == -1) { //返回 -1 時,模組開啟失敗 LOGE("Hello Stub: failed to open /dev/hello -- %s.", strerror(errno));free(dev); return -EFAULT; } *device = &(dev->common); LOGI("Hello Stub: open /dev/hello successfully."); //LOGI是列印資訊嗎? 在哪定義的? return 0; }

 /*--

shmctl(共用記憶體管理)
所需標頭檔 #include <sys/types.h>#include <sys/shm.h>
函數說明 完成對共用記憶體的控制
函數原型 int shmctl(int shmid, int cmd, struct shmid_ds *buf)
函數傳入值 shmid 共用記憶體標識符
cmd IPC_STAT:得到共用記憶體的狀態,把共用記憶體的shmid_ds結構複製到buf中
IPC_SET:改變共用記憶體的狀態,把buf所指的shmid_ds結構中的uid、gid、mode複製到共用記憶體的shmid_ds結構內
IPC_RMID:刪除這片共用記憶體
buf 共用記憶體管理結構體。具體說明參見共用記憶體核心結構定義部分
函數傳回值 成功:0
出錯:-1,錯誤原因存於error中
錯誤碼 EACCESS:參數cmd為IPC_STAT,確無許可權讀取該共用記憶體EFAULT:參數buf指向無效的記憶體位址EIDRM:標識符為shmid的共用記憶體已被刪除EINVAL:無效的參數cmd或shmidEPERM:參數cmd為IPC_SET或IPC_RMID,卻無足夠的許可權執行

--*/

      DEVICE_NAME定義為"/dev/hello"。由於裝置檔案是在核心驅動裡面通過device_create建立的,而device_create建立的裝置檔案預設只有root使用者可讀寫,而hello_device_open一般是由上層APP來調用的,這些APP一般不具有root許可權,這時候就導致開啟裝置檔案失敗:

       Hello Stub: failed to open /dev/hello -- Permission denied.      解決辦法是類似於Linux的udev規則,開啟Android原始碼工程目錄下,進入到system/core/rootdir目錄,裡面有一個名為ueventd.rc檔案,往裡面添加一行:       /dev/hello 0666 root root       定義hello_device_close、hello_set_val和hello_get_val這三個函數: 
static int hello_device_close(struct hw_device_t* device) {      struct hello_device_t* hello_device = (struct hello_device_t*)device;        if(hello_device) {          close(hello_device->fd);          free(hello_device);      }          return 0;  }    static int hello_set_val(struct hello_device_t* dev, int val) {      LOGI("Hello Stub: set value %d to device.", val);        write(dev->fd, &val, sizeof(val));        return 0;  }    static int hello_get_val(struct hello_device_t* dev, int* val) {      if(!val) {          LOGE("Hello Stub: error val pointer");          return -EFAULT;      }        read(dev->fd, val, sizeof(*val));        LOGI("Hello Stub: get value %d from device", *val);        return 0;  }  
      四. 繼續在hello目錄下建立Android.mk檔案:       LOCAL_PATH := $(call my-dir)       include $(CLEAR_VARS)       LOCAL_MODULE_TAGS := optional       LOCAL_PRELINK_MODULE := false       LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw       LOCAL_SHARED_LIBRARIES := liblog       LOCAL_SRC_FILES := hello.c       LOCAL_MODULE := hello.default       include $(BUILD_SHARED_LIBRARY)      注意,LOCAL_MODULE的定義規則,hello後面跟有default,hello.default能夠保證我們的模組總能被硬象抽象層載入到。      五. 編譯:       USER-NAME@MACHINE-NAME:~/Android$ mmm hardware/libhardware/modules/hello       編譯成功後,就可以在out/target/product/generic/system/lib/hw目錄下看到hello.default.so檔案了。      六. 重新打包Android系統鏡像system.img:       USER-NAME@MACHINE-NAME:~/Android$ make snod       重新打包後,system.img就包含我們定義的硬體抽象層模組hello.default了。      雖然我們在Android系統為我們自己的硬體增加了一個硬體抽象層模組,但是現在Java應用程式還不能訪問到我們的硬體。我們還必須編寫JNI方法和在Android的Application Frameworks層增加API介面,才能讓上層Application訪問我們的硬體。在接下來的文章中,我們還將完成這一系統過程,使得我們能夠在Java應用程式中訪問我們自己定製的硬體。 我用的是友善之臂提供的tiny4412開發板編譯過程中:

1

make:進入目錄'/opt/FriendlyARM/tiny4412/android/android-4.1.2'
make: *** 沒有規則可以建立“out/target/product/generic/obj/SHARED_LIBRARIES/audio.usb.default_intermediates/import_includes”需要的目標“out/target/product/generic/obj/SHARED_LIBRARIES/libc_intermediates/export_includes”。 停止。
make:離開目錄“/opt/FriendlyARM/tiny4412/android/android-4.1.2”

切記:. setenv

 

2 局部程式修改

http://blog.csdn.net/oldmtn/article/details/9213869

  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.