新增LED設(shè)備--從上層到底層理解安卓架構(gòu)之HAL篇
硬件抽象層介紹
+
1)不是所有的硬件設(shè)備都有標(biāo)準(zhǔn)的Linux內(nèi)核接口,通過HAL層封裝了一套固定的向上接口,可以使得上層的開發(fā)邏輯更清晰簡(jiǎn)單。HAL框架是固定的,開發(fā)人員只需要按照框架開發(fā)即可,無需關(guān)注與上層的交互上,將精力放在HAL層本身的實(shí)現(xiàn)上即可。
2)從商業(yè)角度,硬件廠商可以把一些核心的算法、調(diào)試參數(shù)、實(shí)現(xiàn)邏輯等放在HAL層而不是kenel層,kenel層只是簡(jiǎn)單與硬件做數(shù)據(jù)交互。這樣的好處是可以不用遵Linux的GPL開源協(xié)議,保護(hù)自身的商業(yè)機(jī)密。
Hal架構(gòu)圖
模塊類型結(jié)構(gòu)體hw_module_t,設(shè)備類型結(jié)構(gòu)體hw_device_t,
兩個(gè)結(jié)構(gòu)體的詳細(xì)內(nèi)容可以參考源碼路徑:/hardware/libhardware/include/hardware/hardware.h。HAL層開發(fā)主要工作是建立好自定義的結(jié)構(gòu)體,并實(shí)現(xiàn)hw_device_t的內(nèi)部的幾個(gè)關(guān)鍵函數(shù)。
頭文件hardware/libhardware/include/hardware/testled_hal.h
struct testled_module_t {
struct hw_module_t common;
};
struct testled_device_t {
struct hw_device_t common;
int (*open)(void);
int (*control)(int on);
};
頭文件內(nèi)申明了led的兩個(gè)關(guān)鍵結(jié)構(gòu)體testled_module_t和testled_device_t,結(jié)構(gòu)體的實(shí)現(xiàn)在c文件中。
2)c文件 hardware/libhardware/modules/testled/testled_hal.c
//日志的標(biāo)簽
static int fd;
int testled_hal_dev_close(struct hw_device_t *device)
{
if(device != NULL)
{
struct testled_device_t *temp = (struct testled_device_t *)device;
free(temp);
}
close(fd);
return 0;
}
int testled_hal_open_dev(void)
{
ALOGD("--%s--", __func__);
fd = open("/dev/test-led", O_RDWR);
if(fd < 0)
{
ALOGE("open failed : %s", strerror(errno));
return fd;
}
return 0;
}
int testled_hal_control_dev(int on)
{
ALOGD("--%s--", __func__);
int ret;
switch(on){
case 0:
ret = ioctl(fd, LED1CTRL_ON_CMD,0);
break;
case 1:
ret = ioctl(fd, LED1CTRL_OFF_CMD,0);
break;
case 2:
ret = ioctl(fd, LED2CTRL_ON_CMD,0);
break;
case 3:
ret = ioctl(fd, LED2CTRL_OFF_CMD,0);
break;
default:
break;
}
if(ret < 0){
ALOGE("control failed : %s", strerror(errno));
return ret;
}
return 0;
}
int testled_hal_module_open(const struct hw_module_t *module, const char *id,
struct hw_device_t **device)
{
ALOGD("--%s--", __func__);
struct testled_device_t *led_dev = NULL;
led_dev = (struct testled_device_t *)malloc(sizeof(struct testled_device_t));
if (led_dev == NULL)
{
ALOGE("malloc failed");
return -1;
}
ALOGD("malloc success");
//初始化device對(duì)象
led_dev->common.tag = HARDWARE_DEVICE_TAG;
led_dev->common.version = 1;
led_dev->common.module = module;
led_dev->common.close = testled_hal_dev_close;
led_dev->open = testled_hal_open_dev;
led_dev->control = testled_hal_control_dev;
//將當(dāng)前的led_dev傳遞給jni層
(struct hw_device_t *)led_dev; =
return 0;
}
struct testled_device_t testled_hal_methods = {
open : testled_hal_module_open,
};
struct testled_module_t HAL_MODULE_INFO_SYM = {
common : {
tag : HARDWARE_MODULE_TAG,
version_major : 1,
version_minor : 0,
id : LED_HAL_MODULE_ID,
name : "testled hal module",
methods : &testled_hal_methods,
},
};
主要實(shí)現(xiàn)了hal結(jié)構(gòu)體中的close,open,control函數(shù),并將函數(shù)傳給結(jié)led_dev構(gòu)體。
common.close = testled_hal_dev_close;
led_dev->open = testled_hal_open_dev;
control = testled_hal_control_dev;
Android.mk hardware/libhardware/modules/testled/Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := testled_hal.default
LOCAL_MODULE_RELATIVE_PATH := hw
LOCAL_SRC_FILES := testled_hal.c
LOCAL_SHARED_LIBRARIES := liblog libcutils
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
將c文件編譯成模塊
hardware/libhardware/modules/Android.mk內(nèi)加入testled
三、編譯
模塊編譯
mmm hardware/libhardware/modules/ testled
在out/target/product/nanopc-t4/system/lib/hw/ 目錄下生生成test_led_hal.default.so
全部編譯后,test_led_hal.default.so在設(shè)備的/system/lib/hw路徑下,android frameworks中的JNI調(diào)用led設(shè)備時(shí),通過一系列轉(zhuǎn)換就會(huì)調(diào)用到這個(gè)庫(kù)內(nèi)部的函數(shù),從而調(diào)動(dòng)掉底層的led驅(qū)動(dòng)。
掃碼關(guān)注我們
看更多嵌入式案例
喜歡本篇內(nèi)容請(qǐng)給我們點(diǎn)個(gè)再看
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問題,請(qǐng)聯(lián)系我們,謝謝!