在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


原文:http://blog.csdn.net/luoshengyang/article/details/6573809

  

聯繫我們

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